Уничтожить объект структуры в C #? - PullRequest
20 голосов
/ 27 января 2010

Меня немного смущает тот факт, что в C # сборка мусора происходит только со ссылочными типами. Это означает, что GC выбирает только ссылочные типы для выделения памяти. Так что же происходит с типами значений, поскольку они также занимают память в стеке?

Ответы [ 8 ]

30 голосов
/ 27 января 2010

Для начала, находятся ли они в стеке или в куче, зависит от того, в какой контекст они входят - если они находятся в ссылочном типе, они все равно будут в куче. (В любом случае вы должны учитывать, насколько вы действительно заботитесь о делении стека / кучи - как писал Эрик Липперт, это в значительной степени деталь реализации .)

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

Короткий ответ: вам не нужно об этом беспокоиться :) (Это предполагает, что у вас нет ничего другого , кроме памяти, о которой стоит беспокоиться, конечно - если у вас есть структуры со ссылками на нативные дескрипторы, которые должны быть освобождены, это несколько другой сценарий.)

18 голосов
/ 27 января 2010

Я немного смущен тем фактом, что в C # сборка мусора происходит только с ссылочными типами.

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

struct S { public string str; }
...
S s = default(S); // local variable of value type
s.str = M(); 

когда запускается сборщик мусора, он, безусловно, смотрит на s, потому что он должен определить, что s.str еще жив.

Мое предложение: уточнить точно что вы подразумеваете под глаголом "получает мусор".

GC выбирает только эталонные типы для выделения памяти.

Опять же, это не факт. Предположим, у вас есть экземпляр

class C { int x; }

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

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

Так что же происходит с типами значений, поскольку они также занимают память в стеке?

С ними вообще ничего не происходит. С ними ничего не должно случиться. Стек составляет миллион байтов. Размер стека определяется при запуске потока; он начинается с миллиона байтов и остается миллион байтов на протяжении всего выполнения потока. Память в стеке не создается и не уничтожается; изменено только его содержимое.

7 голосов
/ 27 января 2010

В этом вопросе используется слишком много глаголов, например, уничтожено, исправлено, освобождено, удалено. Это не соответствует тому, что на самом деле происходит. Локальная переменная просто перестает быть, стиль норвежского попугая .

Метод имеет одну точку входа, первое, что происходит, это то, что указатель стека ЦП настроен. Создание «стекового фрейма», места для хранения локальных переменных. CLR гарантирует, что это пространство инициализируется равным 0, в противном случае функция, которую вы строго используете в C # из-за определенного правила назначения.

Метод имеет единственную точку выхода, даже если код метода заполнен несколькими операторами return. В этот момент указатель стека просто восстанавливается до своего первоначального значения. По сути, он «забывает», что локальные переменные там, где они есть. Их значения никак не «очищаются», байты все еще там. Но они не будут длиться долго, следующий вызов в вашей программе перезапишет их снова. Правило нулевой инициализации CLR гарантирует, что вы никогда не сможете наблюдать те старые значения, которые были бы небезопасными.

Очень, очень быстро, занимает не более одного цикла процессора. Видимым побочным эффектом этого поведения в языке C # является то, что типы значений не могут иметь финализатор. Обеспечение того, чтобы не было никакой дополнительной работы.

3 голосов
/ 27 января 2010

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

3 голосов
/ 27 января 2010

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

0 голосов
/ 26 марта 2015

Каждый экземпляр типа значения в .NET будет частью чего-то еще, что может быть большим включающим экземпляр типа значения, объектом кучи или фреймом стека. Всякий раз, когда возникает какая-либо из этих вещей, любые структуры внутри них также возникают; эти структуры будут продолжать существовать до тех пор, пока существует то, что их содержит. Когда вещь, которая содержит структуру, перестает существовать, структура также будет существовать. Нет способа уничтожить структуру, не разрушив контейнер, и нет способа уничтожить что-либо, содержащее одну или несколько структур, не разрушая содержащиеся в нем структуры.

0 голосов
/ 27 января 2010

Также хотелось бы добавить, что стек находится на уровне потока, а куча - на уровне домена приложения.

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

0 голосов
/ 27 января 2010

типов значений будут освобождены, когда кадр стека будет удален после того, как он был выполнен, я бы предположил

...