Сомнения относительно сборщика "мусора".NET

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

1) GC.Collect () называют частичное или полный набор? 2) Действительно ли частичный набор блокирует выполнение приложения "жертвы"? Если да.. затем я предполагаю, что это - очень "легкие" вещи сделать, так как я выполняю игровой сервер, который использует 2-3GB из памяти, и у меня "никогда" нет остановок выполнения (или я не вижу их..). 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();
    }

B будет когда-либо иметь право быть собранным "мусор" (прежде чем DoSomeLongWork закончится)? Ссылка на b, который содержит classList, это можно считать корнем? Или корень является только первой ссылкой на экземпляр? (я имею в виду, b является корневой ссылкой, потому что инстанцирование происходит там).

9
задан Smjert 8 April 2010 в 00:40
поделиться

5 ответов

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

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

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

5
ответ дан 3 November 2019 в 00:00
поделиться
  1. Да, GC.Collect () выполняет полный сбор, но вы можете выполнить GC.Collect вручную (0) делать только Gen 0.

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

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

1
ответ дан 3 November 2019 в 00:00
поделиться

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

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

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

Checkout Основные сведения о сборщике мусора и советы по производительности

2
ответ дан 3 November 2019 в 00:00
поделиться
  1. GC.Collect () выполняет полный сбор данных. Вот почему не стоит называть это самостоятельно, так как это может преждевременно продвигать объекты до поколения

  2. AFAIK, не совсем. GC блокирует так мало времени, что это несущественно.

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

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

3
ответ дан 3 November 2019 в 00:00
поделиться

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

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

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

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

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

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

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

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

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

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

1
ответ дан 3 November 2019 в 00:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: