Возможно ли, что утечка памяти может происходить и в стеке в .NET? - PullRequest
5 голосов
/ 25 февраля 2010

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

А как насчет стека? И насколько я знаю, GC не несет ответственности за очистку стека, он будет автоматически очищен, когда функция вернется.

Итак, мой вопрос заключается в том, есть ли вероятность того, что утечка памяти произойдет и в стеке? Если да, то при каком сценарии и каковы наилучшие методы для предотвращения утечки такого рода.

Ответы [ 6 ]

2 голосов
/ 25 февраля 2010

Если вы пишете рекурсивные функции, которые хранят локальные стековые ссылки на больших данных, которые не нужны при субрекурсивных вызовах, то это тип утечки пространства, но очень редко бывает так, чтобы это было проблемой на практике .

В целом, если у вас есть что-то вроде

Main() {
    var s = ReadInAGiganticString();   // say 10 Megs long
    Server(s.Substring(0,5));          // but I only care about first 5 chars
}
Server(s) {
    while(true) { ... }                // but 10M is on stack forever
}

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

Main() {
    var s = ReadInAGiganticString();
    var t = s.Substring(0,5);
    s = null;                         // the fix
    Server(t);
}
Server(s) {
    while(true) { ... }
}

В общем, если у вас когда-либо есть гигантская переменная в стеке непосредственно перед вызовом, который будет длиться «долго», и эта переменная больше не будет использоваться, вы можете обнулить ее, чтобы убедиться, что она может быть перед GC'd входя в «длинный» вызов.

(Возможно, что оптимизатор может сделать это для вас на основе анализа достижимости.)

Обратите внимание, что приведенный выше ответ предназначен для ссылок на объекты, выделенные в куче, которые находятся в стеке. Если, с другой стороны, у вас есть выделенная в стеке память (например, гигантская структура или stackalloc thingie), то это исправить не так просто, но на практике это еще реже (кто когда-либо создает гигантские структуры?).

1 голос
/ 25 февраля 2010

Утечка памяти может произойти, если вам не удастся правильно освободить неуправляемые ресурсы. Поэтому я боюсь, что если вы отправите управляемый объект в метод, и этот объект обернет неуправляемый ресурс, и он не сможет правильно освободить неуправляемый ресурс, произойдет утечка памяти. Стек освободит управляемую ссылку, но неуправляемый ресурс останется живым.

0 голосов
/ 25 февраля 2010

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

0 голосов
/ 25 февраля 2010

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

Если ваш стек каким-то образом выровнен, у вас будут гораздо большие проблемы, чем утечка памяти.

Обычно параметры метода и возвращаемые значения хранятся в стеке (если не оптимизированы для отправки через регистры процессора).

0 голосов
/ 25 февраля 2010

Как вы говорите, GC не очищает стек. Однако пространство, используемое стеком, освобождается при размотке. Таким образом, когда стек извлечен, указатель стека перемещается назад, и, таким образом, пространство может быть использовано повторно.

Недостаточно места в стеке вызовет исключение StackOverflowException. Обычно это происходит из-за ошибки программирования с неограниченной рекурсией.

0 голосов
/ 25 февраля 2010

Переменные, размещенные в стеке, уничтожаются после окончания блока. Так что утечка памяти не может произойти. Практика заключается в создании переменной, которая используется только в данном блоке за пределами этого блока

...