Console.WriteLine("Gen 1 has been swept {0} times",
GC.CollectionCount(1)); // Количество сборок для поколения 1
Console.WriteLine("Gen 2 has been swept {0} times",
GC.CollectionCount(2)); // Количество сборок для поколения 2
Console.ReadLine();
Здесь в целях тестирования преднамеренно был создан большой массив типа object (состоящий из 50000 элементов). Ниже показан вывод программы:
***** Fun with System.GC *****
Estimated bytes on heap: 75760
This OS has 3 object generations.
Zippy is going 100 MPH
Generation of refToMyCar is: 0
Forcing Garbage Collection
Generation of refToMyCar is: 1
Generation of tonsOfObjects[9000] is: 1
Gen 0 has been swept 1 times
Gen 1 has been swept 0 times
Gen 2 has been swept 0 times
К настоящему моменту вы должны лучше понимать детали жизненного цикла объектов. В следующем разделе мы продолжим изучение процесса сборки мусора, обратившись к теме создания
Построение финализируемых объектов
В главе 6 вы узнали, что в самом главном базовом классе .NET Core, System.Object, определен виртуальный метод по имени Finalize(). В своей стандартной реализации он ничего не делает:
// System.Object
public class Object
{
...
protected virtual void Finalize() {}
}
За счет переопределения метода Finalize() в специальных классах устанавливается специфическое место для выполнения любой логики очистки, необходимой данному типу. Учитывая, что метод Finalize() определен как защищенный, вызывать его напрямую из экземпляра класса через операцию точки нельзя. Взамен метод Finalize(), если он поддерживается, будет вызываться
На заметку! Переопределять метод Finalize() в типах структур не разрешено. Подобное ограничение вполне логично, поскольку структуры являются типами значений, которые изначально никогда не размещаются в куче и, следовательно, никогда не подвергаются сборке мусора. Тем не менее, при создании структуры, которая содержит неуправляемые ресурсы, нуждающиеся в очистке, можно реализовать интерфейс iDisposable (вскоре он будет описан). Вспомните из главы 4, что структуры ref и структуры ref, допускающие только чтение, не могут реализовывать какой-либо интерфейс, но могут реализовывать метод Dispose().
Разумеется, вызов метода Finalize() будет происходить (в итоге) во время "естественной" сборки мусора или в случае ее принудительного запуска внутри кода с помощью GC.Collect(). В предшествующих версиях .NET (но не в .NET Core) финализатор каждого объекта вызывался при окончании работы приложения. В .NET Core нет никаких способов принудительного запуска финализатора даже при завершении приложения.
О чем бы ни говорили ваши инстинкты разработчика, подавляющее большинство классов C# не требует написания явной логики очистки или специального финализатора. Причина проста: если в классах используются лишь другие управляемые объекты, то все они в конечном итоге будут подвергнуты сборке мусора. Единственная ситуация, когда может возникнуть потребность спроектировать класс, способный выполнять после себя очистку, предусматривает работу с
В рамках платформы .NET Core неуправляемые ресурсы получаются путем прямого обращения к API-интерфейсу операционной системы с применением служб вызова платформы (Platform Invocation Services — P/Invoke) или в сложных сценариях взаимодействия с СОМ. С учетом сказанного можно сформулировать еще одно правило сборки мусора.