Я прочитал в этой презентации http://golang.org/doc/ExpressivenessOfGo.pdf страница 42:
Safe
- переполнение стека
Как это возможно? и/или как работает Go, чтобы этого избежать?
Я прочитал в этой презентации http://golang.org/doc/ExpressivenessOfGo.pdf страница 42:
Safe
- переполнение стека
Как это возможно? и/или как работает Go, чтобы этого избежать?
Это функция, называемая "сегментированные стеки": каждый goroutine имеет свой собственный стек, выделен в куче.
В простейшем случае реализации языка программирования используют один стек для каждого процесса/адресного пространства, обычно управляемый с помощью специальных инструкций процессора под названием push
и pop
(или что-то в этом роде) и реализованных как динамический массив кадров стека начиная с фиксированного адреса (обычно в верхней части виртуальной памяти).
Это (или используется) быстро, но не особенно безопасно. Это вызывает проблемы, когда много кода выполняется одновременно в одном и том же адресном пространстве (потоках). Теперь каждому нужен свой собственный стек. Но тогда все стеки (кроме, возможно, одного) должны быть фиксированными, чтобы они не перекрывались друг с другом или с кучей.
Тем не менее, любой язык программирования, который использует стек, может быть реализован путем управления стеком по-другому: используя структуру данных списка или аналогичную структуру, которая содержит фреймы стека, но фактически распределена в куче. Там нет до заполнения кучи.он использует сегментированный стек. Что в основном означает, что он использует связанный список вместо массива фиксированного размера, когда он стек. Когда он заканчивается, он делает стек немного больше.
изменить:
Вот еще информация: http://golang.org/doc/go_faq.html#goroutines
Причина, по которой это так здорово, заключается не в том, что она никогда не будет переполняться (это хороший побочный эффект), это то, что вы можете создавать потоки с действительно небольшим объемом памяти, а это значит, что у вас их много.
Я не думаю, что они могут "полностью" избежать. Они обеспечивают способ предотвращения наиболее типичных ошибок, связанных с программированием, для создания.
Когда память заканчивается, невозможно предотвратить переполнение стека.
Даже C может сделать это с помощью нескольких ограничений, которые в основном влияют на компилятор.
Это впечатляющий ум, но не дизайн языка.
Я думаю, что они здесь ссылаются на то, что доступ к массивам всегда проверяется на фактическую длину массива, таким образом отключая один из самых распространенных способов, с помощью которых C-программы случайно выходят из строя или вредоносны.
Например:
package main
func main() {
var a [10]int
for i:= 0; i < 100; i++ {
a[i] = i
}
}
будет panic
с ошибкой во время выполнения, когда он попытается обновить несуществующий 11-й элемент массива. C будет каракули над кучей и, вероятно, также рухнет, но неконтролируемым образом. Каждый массив знает свою длину. В некоторых случаях для компилятора будет возможность оптимизировать проверки, если он может доказать, что они не нужны. (Или достаточно умный компилятор, возможно, статически обнаруживает проблему в этой функции.)
Многие другие ответы говорят о макете памяти в стеке, но это действительно не актуально: вы можете также атаковать переполнение кучи.
В основном указатели Go всегда должны быть типов, с массивами и другими типами, если вы специально не используете пакет unsafe
.