Delphi. ARC. Основные моменты

Читаю книгу Delphi Memory Management, делаю небольшой конспект основных моментов. Учился под музыку Emy Care Read my Mind

Automatic Reference Counting – система, в которой использование каждого объекта отслеживается по ссылкам на него. Что это дает? Простоту кодирования. Например, мы можем писать так…

Вместо традиционного…

Но когда же уничтожается объект? В момент, когда число ссылок на него станет равным нулю.


Золотое правило ARC

Ссылка на объект или интерфейс должна либо быть равна nil, либо указывать на существующий объект в памяти


Если мы пишем через интерфейсы, то в момент входа в контекст ссылка будет равна nil, например

Виды ссылок

Сильные – участвуют в подсчете ссылок на объект

Слабые – не участвуют в подсчете ссылок на объект.

Виды слабых ссылок

[weak] – не участвуют в подсчете ссылок (ARC), когда объект уничтожается, ссылка обнуляется. Поэтому у нас нет “висящих ссылок, указывающих в никуда”. Система следит за этими ссылками и обнуляет их автоматически. Когда этих ссылок много – может возникнуть проблема производительности.

[unsafe] – не участвуют в подсчете ссылок (ARC), когда объект уничтожается, ссылка НЕ обнуляется. Поэтому потенциально возможна проблема “висящих ссылок”

Pointer – начиная с Delphi 10.1 Berlin, можно использовать указатели, они будут работать также как [unsafe], но нужны также ещё касты…

Параметры, отмеченные как const или [ref], также не будут участвовать в механизме подсчета ссылок (ARC).


Каждый объект должен иметь хотя бы одну сильную ссылку, чтобы существовать, иначе он будет уничтожен.


Циклы сильных ссылок

Вот простой пример. На Bar у нас 2 ссылки, поэтому он не уничтожится нормальным образом через ARC. Нужно такие циклы распознавать и разбивать слабыми ссылками. Цепочки зависимостей могут быть самыми разными, но в целом картинка выглядит так, что ссылки в ARC работают правильно, если они выстроены как дерево, а не граф. В общем, никаких обратных сильных ссылок, сильные ссылки только вперед. Если нужна ссылка обратно, делаем ее слабой, то есть так…

Другой способ разбить ссылку занилить таким образом


Классический пример цикла и его разбиения в ARC через классы Parent Child

Тоже самое в коде

Такой код хорошо отработает в ручном режиме управления памятью,

но ARC компилятор даст утечку памяти.

Тоже самое через интерфейсы

Разобьем этот цикл следующим образом

В коде это будет выглядеть так

или так

Все отработает как нужно…

Если у нас Child работает в виде класса, то уничтожать его надо будет ручками, то есть так…

Когда использовать [unsafe] и безопасно ли это?

Когда время жизни ссылки меньше или равно времени жизни объекта, на который она указывает. В контексте объектов Parent Child, Parent можно было бы пометить ссылкой [unsafe], при условии, что Parent никогда не переживет Child.

Смешивание интерфейсных ссылок и ссылок на объекты – ать по рукам!

Смешивать их не надо, это может привести к непредсказуемым последствиям.

Другой пример – метод System.SysUtils.Supports

Здесь мы создаем экземпляр класса, и далее пытаемся проверить поддерживает ли он интерфейс, а метод Supports запускает механизм ARC и уничтожает объект.

Если мы объявим Foo через интерфейс, то все получится как нужно.

Отключение ARC

Используем как обычный класс

Класс Хамелеон

Примеры использования

Утечка памяти при const параметре

Возможное решение, которое отложит проблему – убрать параметр const

Ещё одно решение

И ещё одно

В общем решение в том, чтобы не создавать объекты inline


Коллекции для интерфейсов

IInterfaceList

Или так

System.Generics.Collections.TList<T>

 

This entry was posted in Без рубрики. Bookmark the permalink.

Leave a Reply