Первый вопрос, который возникает у большинства разработчиков Java, заключается в том, как управление памятью реализовано с помощью J2ObjC, поскольку в Java есть сборка мусора, а в Objective-C ее нет по умолчанию. В iOS есть два метода управления памятью : подсчет ссылок и автоматический подсчет ссылок (ARC).
J2ObjC генерирует различный код управления памятью, в зависимости от выбранного метода. Переведите с помощью опции -use-arc
, чтобы сгенерировать код, использующий ARC. По умолчанию используется ручной подсчет ссылок.
Подсчет ссылок
Метод подсчета ссылок делает владение объектом явным. Метод владеет объектом с момента его создания, пока не освободит этот объект. При получении объекта из другого метода принимающий метод сохраняет объект, если на него необходимо ссылаться после возврата метода. Когда методу больше не нужно ссылаться на объект, он должен освободить его. Когда счетчик сохранения объекта равен нулю, его память освобождается и объект больше не действителен. Когда объекты освобождаются, вызывается их метод Dealloc(), чтобы освободить владение их переменными экземпляра.
Одна из проблем этого метода заключается в том, как передать право собственности на объект. Например, для создания объекта может быть вызван фабричный метод. Если фабричный метод освобождает объект перед его возвратом (поскольку он больше не хочет владеть объектом), то этот объект освобождается до того, как вызывающий метод сможет его сохранить.
Чтобы передать право собственности на объект, метод отправляет ему сообщение об автоматическом выпуске (вместо сообщения о выпуске), которое откладывает сообщение о выпуске. Это позволяет фабричному методу создать возвращаемый объект и отказаться от владения им, не делая объект недействительным. Через регулярные промежутки времени (например, после каждой итерации цикла событий в приложении iOS) пул автоматического выпуска «опустошается», то есть всем объектам в этом пуле отправляются сообщения отложенного выпуска. Любые объекты, счетчик сохранения которых упал до нуля, освобождаются как обычно.
Поскольку бремя управления памятью лежит на разработчике, с помощью метода подсчета ссылок легко утечь память. Однако Apple рекомендует некоторые рекомендации по минимизации этой проблемы, которые реализует J2ObjC.
Существует также поддержка среды выполнения и инструментов для обнаружения утечек памяти. Среда выполнения Objective-C сообщает о любых обнаруженных утечках при выходе из приложения, что является одной из причин, по которой J2ObjC преобразует тесты JUnit в исполняемые двоичные файлы. Xcode использует Clang, и этот компилятор имеет отличный статический анализ проблем с памятью, который Xcode делает доступным с помощью своей команды Анализировать.
Автоматический подсчет ссылок (ARC)
ARC — это рекомендуемый Apple метод управления памятью. Он передает ответственность за подсчет ссылок на компилятор, который добавляет соответствующие методы сохранения, выпуска и автоматического выпуска во время компиляции. ARC поддерживает слабые ссылки для устройств под управлением iOS 5 и более поздних версий.
Мы рекомендуем проектам использовать ARC для переведенного кода. Транспилированный код Objective-C аналогичен написанному вручную коду Objective-C. Использование ARC может помочь разработчикам избежать распространенных ошибок, связанных с памятью, таких как чрезмерное освобождение или недостаточное количество ссылок, что делает управление памятью более простым и менее подверженным ошибкам.
Обратите внимание, что ARC по умолчанию не защищен от исключений . В частности, происходит утечка памяти при возникновении исключений. Поскольку исключения более распространены в Java и обычно их можно восстановить, это может быть проблематичным. Использование -fobjc-arc-exceptions
при компиляции с помощью arc устранит утечки с приемлемым снижением производительности.
Мы также рекомендуем новым проектам использовать ARC для написанного вручную кода Objective-C и переходить к подсчету ссылок вручную только в том случае, если данные профилирования показывают реальную проблему с производительностью. Как код ARC, так и код, не поддерживающий ARC, можно без проблем скомпилировать и связать в одно и то же приложение.
Слабые ссылки
Поля могут быть аннотированы с помощью com.google.devtools.j2objc.Weak , который транспилятор использует для создания полей, соответствующих семантике слабых ссылок Objective-C. При использовании подсчета ссылок это означает, что поле не сохраняется при инициализации и автоматически освобождается при освобождении содержащего его экземпляра. При использовании ARC слабые поля помечаются аннотацией __unsafe_unretained
, а связанные свойства объявляются слабыми.
В некоторых случаях экземпляр внутреннего класса попадает в ссылочный цикл со своим внешним экземпляром. Здесь аннотация com.google.devtools.j2objc.WeakOuter используется для обозначения внутреннего класса, поэтому ссылка на внешний класс обрабатывается, как описано выше. Эта аннотация не влияет на другие поля внутреннего класса.
J2ObjC также поддерживает класс WeakReference
, поэтому код Java, использующий его, будет работать таким же образом при переводе. Имейте в виду, что WeakReference
по своей сути недетерминирован в JVM; приложения, которые хотят избежать утечек памяти, сохраняя при этом предсказуемость, вместо этого должны предпочесть @Weak
и @WeakOuter
.
Инструменты управления памятью
- Инструмент Cycle Finder — анализирует исходные файлы Java на наличие сильных циклов ссылок на объекты.
- Xcode Instruments — набор инструментов профилирования Xcode.
- Диагностика памяти Xcode — параметры сборки для работы с диагностикой памяти и ведением журнала.