Я прочитал в этой презентации http://golang.org/doc/ExpressivenessOfGo.pdf стр. 42:
Безопасно
– без переполнения стека
Как это возможно? и/или как Go работает, чтобы избежать этого?
Я прочитал в этой презентации http://golang.org/doc/ExpressivenessOfGo.pdf стр. 42:
Безопасно
– без переполнения стека
Как это возможно? и/или как Go работает, чтобы избежать этого?
Это функция под названием «сегментированные стеки»: каждая горутина имеет свой собственный стек, размещенный в куче.
В простейшем случае реализации языка программирования используют один стек для каждого процесса/адресного пространства, обычно управляемый специальными инструкциями процессора, называемыми 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.