Почему у Go нет стековых потоков - PullRequest
20 голосов
/ 19 ноября 2010

Я прочитал в этой презентации http://golang.org/doc/ExpressivenessOfGo.pdf стр. 42:

Сейф

- без переполнения стека

Как это возможно? и / или как Go работает, чтобы избежать этого?

Ответы [ 5 ]

16 голосов
/ 19 ноября 2010

Эта функция называется «сегментированные стеки»: каждая процедура имеет свой собственный стек, выделяется в куче .

В простейшем случае реализации на языке программирования используют один стек на процесс/ адресное пространство, обычно управляемое с помощью специальных инструкций процессора, называемых push и pop (или что-то в этом роде) и реализованных в виде динамического массива стековых фреймов, начинающихся с фиксированного адреса (обычно это вершина виртуальной памяти).*

Это (или раньше) быстро, но не особо безопасно.Это вызывает проблемы, когда много кода выполняется одновременно в одном и том же адресном пространстве (потоки).Теперь каждому нужен свой стек.Но тогда все стеки (кроме, возможно, одного) должны быть фиксированного размера, чтобы они не перекрывались друг с другом или с кучей.

Однако любой язык программирования, использующий стек, также может быть реализован путем управлениястек по-другому: используя структуру данных списка или аналогичную, которая содержит кадры стека, но фактически размещается в куче.Нет переполнения стека, пока куча не заполнится.

5 голосов
/ 19 ноября 2010

он использует сегментированный стек. Что в основном означает, что он использует связанный список вместо массива фиксированного размера в качестве стека. Когда ему не хватает места, стек становится немного больше.

редактирование:

Вот еще немного информации: http://golang.org/doc/go_faq.html#goroutines

Причина, по которой это так здорово, не в том, что он никогда не переполнится (это хороший побочный эффект), а в том, что вы можете создавать потоки с очень маленьким объемом памяти, то есть их может быть много.

2 голосов
/ 19 ноября 2010

Я не думаю, что они могут "полностью" избежать переполнения стека. Они обеспечивают способ предотвращения наиболее типичных ошибок программирования, приводящих к переполнению стека.

Когда память заканчивается, невозможно предотвратить переполнение стека.

0 голосов
/ 22 ноября 2010

Я думаю, что они ссылаются здесь на то, что доступ к массивам всегда проверяется по фактической длине массива, таким образом отключая один из наиболее распространенных способов случайного сбоя или сбоя программ на Си.

Например:

package main

func main() {
    var a [10]int

    for i:= 0; i < 100; i++ {
        a[i] = i
    }
}

будет panic с ошибкой во время выполнения при попытке обновить несуществующий 11-й элемент массива. С мог бы набросаться на кучу и, вероятно, тоже потерпеть крах, но неконтролируемым образом. Каждый массив знает свою длину. В некоторых случаях у компилятора будет возможность оптимизировать проверки, если он сможет доказать, что они не нужны. (Или достаточно умный компилятор может статически обнаружить проблему в этой функции.)

Многие другие ответы говорят о расположении памяти в стеке, но на самом деле это не имеет значения: у вас также могут быть атаки переполнения кучи.

В основном, указатели Go всегда должны быть безопасными с типами, с массивами и другими типами, если вы специально не используете пакет unsafe.

0 голосов
/ 19 ноября 2010

Даже C может сделать это с несколькими ограничениями, которые в основном влияют на компилятор.

Это впечатляющий подвиг, но не языковой дизайн.

...