Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2213 / 889 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 10:

Управление памятью и сборка мусора

Пример на сборку мусора

Пример на сборку мусора

using System;
using System.Collections;
class GarbageClass {
    public static int Main(String[] args) {
      // ArrayList object created in heap, myArray is now a root
      ArrayList myArray = new ArrayList();
      // Create 10000 objects in the heap
      for (int x = 0; x < 10000; x++) {
         myArray.Add(x.ToString()); //Object created in heap
      }
     
      foreach (object currValue in myArray)
      {
         string s = (string)currValue;
         Console.WriteLine (s);
      }
  
      System.GC.Collect (GC.GetGeneration(myArray[0]));
      return 0;
   }
}

Проиллюстрируем основные концепции сборки мусора на простом примере. На слайде приведен класс GarbageClass, главный метод которого создает список myArray, а затем в цикле добавляет в этот список 10 000 строковых объектов. Все эти объекты создаются в куче; время их жизни распространяется до конца метода Main.

Затем все элементы myArray перебираются в цикле foreach, и значение каждого элемента печатается на экран. При этом на каждой итерации цикла происходит создание объекта в куче (это, конечно же, жутко неэффективно - по-хорошему надо было бы передавать currValue непосредственно в метод WriteLine, но мы как раз хотим продемонстрировать пример, в котором много мусора).

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

Интерфейс компилятора со сборщиком мусора

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

Однако в .NET необходимости в таком интерфейсе не возникает, так как сборщик мусора может самостоятельно получить всю необходимую ему информацию во время исполнения программы от библиотек динамической поддержки .NET. Это становится возможным благодаря тому, что .NET использует единую систему типов (Common Type System, см. "Введение и обзор платформы .NET" ) и запрещает потенциально опасные преобразования данных. Единственная трудность, связанная с использованием такого решения, может возникнуть при реализации компиляторов с языков, обладающих системой типов данных, отличной от .NET. В этом случае типы данных, специфические для реализуемого языка придется эмулировать с помощью типов .NET или путем создания специального класса, реализующего необходимую функциональность.

С другой стороны, в компиляторах, генерирующих ассемблерный код, интерфейс между компилятором и сборщиком мусора практически неизбежен, так как даже в простейших случаях невозможно провести различие между некоторыми типами данных - например, непонятно, как можно определить по 4-байтовому значению, является ли оно простым целым числом или указателем. Информация такого рода теряется в процессе компиляции и потому должна специально сохраняться для сборщика мусора.

Литература к лекции

  • Д. Кнут "Искусство программирования", Вильямс, 2000
  • J. Richter "Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework", Parts 1 & 2, MSDN Magazine, November 2000 / December 2000
  • Microsoft C# Language Specification, Microsoft Press, 2001