2010-04-08 3 views
9

Я читал некоторые документы о .NET сборщика мусора, но я до сих пор есть некоторые сомнения (примеры в C#):Сомнения .NET сборщика мусора

1) Имеет ли GC.Collect() называют частичное или полная коллекция? 2) Выполняет ли частичная сборка выполнение приложения «жертва»? Если да, то я предполагаю, что это очень «легкие» вещи, которые нужно делать, так как я запускаю игровой сервер, который использует 2-3 ГБ памяти, и у меня «никогда» нет остановки выполнения (или я не вижу их.). 3) Я читал о корнях GC, но до сих пор не могу понять, как именно они работают. Предположим, что это код (C#):

MyClass1:

[...] 
public List<MyClass2> classList = new List<MyClass2>(); 
[...] 

Главная:

main() 
    { 
    MyClass1 a = new MyClass1(); 
    MyClass2 b = new MyClass2(); 
    a.classList.Add(b); 

    b = null; 

    DoSomeLongWork(); 
    } 

Будет ли когда-нибудь б иметь право быть мусора (до завершения работы DoSomeLongWork)? Ссылка на b, что содержит классList, может ли он считаться корнем? Или корень - это только первая ссылка на экземпляр? (я имею в виду, что b - это корневая ссылка, потому что там создается экземпляр).

ответ

5
  1. Есть несколько перегрузок для GC.Collect. Тот, у кого нет каких-либо параметров, полностью собирает. Но имейте в виду, что редко бывает полезно называть GC явно.

  2. Сбор мусора происходит в управляемом приложении. GC может потребоваться приостановить все управляемые потоки в этом процессе, чтобы сжать кучу. Это не влияет на другие процессы в системе, если это то, о чем вы просите. Для большинства приложений это обычно не проблема, но вы можете столкнуться с проблемами, связанными с производительностью, из-за частых сборов. Существует несколько подходящих счетчиков производительности (% времени в GC и т. Д.), Которые вы можете использовать для контроля выполнения GC.

  3. Подумайте о корне как действительной ссылке. В вашем примере экземпляр MyClass2 не будет собран, если есть ссылки на него. То есть если экземпляр, на который указывает a, все еще укоренен, будет ваш экземпляр MyClass2. Кроме того, имейте в виду, что GC намного более агрессивен в режимах выпуска, чем сборки отладки.

3
  1. GC.Collect() делает полную коллекцию. Вот почему не рекомендуется называть это самим, так как это может преждевременно продвигать объекты до поколения

  2. AFAIK, не совсем. ГК блокирует столь малое время, чтобы быть несущественным.

  3. Пакет GC GC является объектом, на который в настоящее время ссылается метод в стеке. Обратите внимание, что поведение между версиями debug и release отличается. при построении отладки все переменные в методе сохраняются до тех пор, пока метод не вернется (так что вы можете увидеть их значение в окне отладки). При выпуске релизов CLR отслеживает, где используются переменные метода, и GC может удалять объекты, на которые ссылается текущий исполняемый метод, но не используется в разделе метода, который еще предстоит выполнить.

Таким образом, в вашем примере, как a и b не ссылаются снова после DoSomeLongWork() вызова, так и в версии релиза, при этом выполнения метода они оба иметь право на инкассо. В отладочных сборках они будут зависать до тех пор, пока не вернется метод main().

+0

О вашем третьем ответе, почему вы говорите «если строка b = null не была там»? Если линия WAS там, то вещи, которые вы описали (в режиме выпуска), не произойдет? И я все еще не могу понять, работает ли ссылка в Списке в качестве действительной ссылки, или если я делаю b = null, а затем запускает сборщик мусора, я обнаружил бы, что ссылка List ссылается на null. – Smjert

+0

Извините, я отредактировал мое сообщение. Ссылка в списке не считается корнем, потому что вы можете добраться до нее только через 'a' - и этот объект имеет право на сбор, поэтому список имеет право (если ничего не ссылается на него), поэтому' b' имеет право , – thecoop

+0

a и b не ссылаются снова * до * DoSomeLongWork. Они оба будут собирать мусор, если GC происходит, когда DoSomeLongWork работает. Это не может вызвать проблемы, поскольку ссылки отсутствуют. –

2

Сбор мусора automatic. Вам не нужно вмешиваться, если вы не имеете дело с неуправляемыми ресурсами. Мусор собирается всякий раз, когда объект выходит из сферы действия; и в определенные интервалы времени всякий раз, когда сборщик мусора считает нужным - например, ОС требует памяти. Это означает, что нет гарантии того, как скоро это произойдет, но ваше приложение не исчерпает память, прежде чем память от этих объектов будет исправлена.

Будет ли когда-либо иметь возможность собирать мусор (до завершения DoSomeLongWork)?

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

заказ Garbage Collector Basics and Performance Hints

1
  1. Да, GC.Collect() выполняет полный сбор, но вы можете сделать руководство GC.Collect (0), чтобы сделать только gen 0.

  2. Все коллекции блокируют потоки, но частичный сбор делает это только очень кратко.

  3. Нет, экземпляр MyClass2 по-прежнему доступен в другом списке. Оба a и b являются справочными ссылками (во время DoSomeLongWork), но поскольку b имеет значение null, это не имеет значения. Обратите внимание, что GC очень привязан к концепции ссылочных типов. b - это только локальный var, ссылающийся на анонимный объект. «Корни» для GC - это статические поля, все в стеке и даже регистры процессора. Проще: все, к чему у вашего кода еще есть доступ.

+0

AFAIK, 3 неверно. CLR отслеживает, где переменные ссылаются в методе и может собирать мусор до этого – thecoop

+0

@thecoop: Нет, оптимизатор JIT может прекратить ссылку 'b' раньше, но поскольку экземпляр находится в другом списке, здесь нет никакой разницы. Обычно это происходит. –

+0

@ thecoop: Я вижу, возможно, что 'a' оптимизирован раньше, но это не было целью вопроса. –

1

Будет ли когда-нибудь б иметь право быть мусора (до завершения работы DoSomeLongWork)?

Потенциально да, при условии a и b исключают из набора глобальных корней компилятора (т.е. не сохраняется в стеке), то они могут быть утилизированы коллекцией во DoSomeLongWork.

Я нашел случаи, когда .NET регенерирует счастливо, но Mono leaks memory.

Ссылка на b, что содержит классList, может ли он считаться корнем?

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

  • Игрушка компилятор может подтолкнуть ссылки из аргументов функции и возвращается из вызовов функций в стек и раскрутку стеки в конце каждой функции. В этом случае b будет вставлен в стек и, следовательно, будет глобальным корнем.

  • Компиляторы качества продукции выполняют сложное распределение регистров и поддерживают только прямые ссылки в стеке, либо перезаписывая, либо обнуляя ссылки на стек при их смерти.В этом случае b мертв во время вызова DoSomeLongWork, поэтому его запись в стек будет отменена или перезаписана.

Ничего из этого не может быть выведено из исходного кода без подробностей о том, что именно сделает компилятор. Например, мой проект HLVM является только игрушкой на этом этапе, используя прежнюю технику, но в действительности это будет собирать a и b, потому что вызов DoSomeLongWork является хвостовым вызовом.

Или корень - это только первая ссылка на экземпляр?

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

Смежные вопросы