Quantcast
Channel: vinxru
Viewing all articles
Browse latest Browse all 319

Мой сборщик мусора

$
0
0
А мне то же пришлось сделать сборщик мусора.

Для расширения функциональности своей программы (когда то давно) я написал собственный язык программирования. Было два главных требования - любая программа на этом языке не должна была приводить к падению всей системы, и язык должен работать с классами и объектами написанными на C++. А главная причина падения - это указатели, поэтому и возникло решение сделать сборщик мусора в стиле Java или .NET.

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

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

Но для кода написанного на C++ (тем более не мной), организовать подсчет ссылок было невозможно. Поэтому, если такой код используется скриптовым языком, то невозможно определить, используется ли объект в данный момент или нет. Надо было все переписывать или делать костыль.

По ходу выполнения программы объекты C++ могут помечаться на уничтожение, но уничтожаются только когда программа завершила выполнение (удаляются в цикле обработки сообщений). Это работает, причем быстрее прошлых двух способов. Но есть и минусы. При "особом уличном программировании"памяти расходуется очень много. Это уже третий способ уничтожения объектов.

Основная проблема ООП и сборщиков мусора в том, что программа создает миллиард объектов. А не в сборщике мусора конкретно. С++ умеет из коробки обходить эту проблему. Внутри объекта можно разместить сотню зависимых объектов и память под них выделится одним блоком.

То есть вместо

class Form1 {
  Button* button1;

  Form1() {
    button1 = new Button;
  }
}


Писать

class Form1 {
  Button button1;
}


Но сборщик мусора не сможет корректно удалить такой объект. Поэтому в каждом объекте был размещен указатель на главный объект, который удалялся только если необходимо было удалить все объекты. То есть программа могла держать указатель на button1. И форма при этом не разрушалась, даже если на форму указателей не было.

class Form1 {
  Button button1;

  Form1() : button1(this) {}
}


Это уже четвертое решение по сборке мусора.

Но есть и пятое решение - это размещение объектов в стеке. И тут есть очевидная проблема. Если на момент выхода из функции и разрушения объекта, кто то сохранил на него указатель, то ни одно решение выше не поможет. Всё в итоге упадет. (Контроль того, что кто то сохранил указатель происходит по счетчику ссылок.)

Поэтому была написана еще одна программа, которая пытается занулить эти указатели. Сделать она это может лишь в скриптовом языке и тот в худшем случае отделается исключением NULL Object. Ну а если это C++ сохранил указатель, то вся программа завершается с ошибкой и указанием номера строки.

Итого:

1) Подсчет ссылок
2) Обход графа
3) Удаление объектов в цикле обработки сообщений
4) Объединение объектов в один блок
5) Размещение объектов в стеке.

Вот такой монстроидальный сборщик мусора получился при попытке скрестить: язык типа Java, язык типа C++ и скорость работы.

Viewing all articles
Browse latest Browse all 319

Latest Images

Trending Articles