Сохраняются ли сопутствующие объекты в памяти на протяжении жизненного цикла приложения - PullRequest
8 голосов
/ 10 января 2020

В Kotlin вы можете создать синглтон, используя сопутствующий объект:

class MyClass {
   companion object {
        fun doSomething() {

        }
    }
}

В соответствии с Kotlin документами, он гласит:

Обратите внимание, что, хотя члены сопутствующих объектов выглядят как элементы stati c на других языках, во время выполнения они все еще являются экземплярами реальных объектов ...

https://kotlinlang.org/docs/reference/object-declarations.html

Означает ли это, что после использования функции в сопутствующем объекте экземпляр класса (MyClass) остается в памяти на протяжении всего жизненного цикла приложения? Есть ли в Android Studio способ проверить, так ли это?

Ответы [ 2 ]

6 голосов
/ 10 января 2020

экземпляр класса (MyClass) остается в памяти на весь жизненный цикл приложения ?

Сопутствующий объект в JVM

в kotlin

class MyClass {
   companion object {
        fun doSomething() {

        }
    }
}

MyClass (Kotlin), преобразованный в JVM

public final class MyClass {
   public static final MyClass.Companion Companion = new MyClass.Companion(null);

   public static final class Companion {
      public final void doSomething() {
      }

      private Companion() {
      }

      public Companion() {
         this();
      }
   }
}

Как указано выше код companion object объявлен как класс Companion в JVM, и он создан как поле static внутри класса MyClass. Таким образом, не собирается г c. Итак, память об объекте (Companion) сохраняется в течение ProcessLifecycle. static final object не выпускается в обычном случае.

В заключение, если упомянуть экземпляр MyClass.Companion в приложении, этот экземпляр не будет собирать мусор. (для общих загрузчиков классов).

* Если в приложении не указан экземпляр MyClass.Companion, его можно удалить с помощью функции сжатия кода .

Есть ли способ в Android Studio проверить, так ли это?

Вы можете видеть сквозь android studio> profiler> Дамп кучи.

Ссылка

0 голосов
/ 10 января 2020

Как вы, похоже, знаете, и приведенный выше ответ также проясняет, что сопутствующие объекты транслируются в классы, и класс, который их объявляет, содержит статическую ссылку c на объект сопутствующего класса, что-то вроде следующего:

public static final MyClass.Companion Companion = new MyClass.Companion(null);

Теперь вопрос

Сохраняются ли сопутствующие объекты в памяти на протяжении жизненного цикла приложения

, поскольку декларирующий класс содержит static ссылку на сопутствующий класс, вопрос сводится к времени жизни static полей в jvm class, и ответ лежит в JVM spe c, но spe c является битом dry в объяснении, так Я добавляю некоторые фрагменты из книги Внутри Java Виртуальная машина .

Как в вашем примере, скажем, у нас есть class только с одним объектом-компаньоном.

Первый вопрос: когда будет создан объект класса-компаньона? или когда static поля инициализируются?

соответствующий текст из книги . (для контекста книга говорит о процедуре загрузки класса)

Инициализация

Последний шаг, необходимый для подготовки класса или интерфейса для его первого активного использования, - это инициализация, процесс установки переменные класса к их надлежащим начальным значениям. Как здесь используется, «правильное» начальное значение - это желаемое начальное значение программиста для переменной класса. Правильное начальное значение контрастирует с начальным значением по умолчанию, заданным для переменных класса во время подготовки. Как описано выше, виртуальная машина назначает значения по умолчанию только на основе типа каждой переменной. Правильные начальные значения, напротив, основаны на каком-то генеральном плане, известном только программисту. В коде Java правильное начальное значение указывается через инициализатор переменной класса или инициализатор stati c.

Итак, мы знаем, что после загрузки и инициализации MyClass объект-компаньон класс будет создан.

но что заставит JVM загрузить MyClass?

Спецификация Java Virtual Machine обеспечивает гибкость реализации во времени загрузки класса и интерфейса и связывания, но строго определяет время инициализации. Все реализации должны инициализировать каждый класс и интерфейс при первом активном использовании. Активное использование класса:

  1. Вызов конструктора для нового экземпляра класса

  2. Создание массива, который имеет класс как свой тип элемента

  3. Вызов метода, объявленного классом (не унаследованного от суперкласса)

4 использование или присвоение поля, объявленного классом (не унаследованного от суперкласса или суперинтерфейса), за исключением полей, которые являются как stati c, так и final, и инициализируются константным выражением времени компиляции

Таким образом, согласно 4-му пункту, когда вы делаете MyClass.foo() из kotlin или MyClass.Companion.foo(), в этот момент MyClass будет загружено и готово. (Вероятно, намного раньше)

Обратите внимание, что на данный момент нет объекта MyClass, то есть мы не использовали выражение MyClass().

Означает ли это static поля будут оставаться в памяти до тех пор, пока приложение работает?

Их можно собирать мусором, если объявленный тип выгружается, в нашем случае, если JVM или ART (на android) выгружает MyClass, тогда есть вероятность, что объект-компаньон будет собирать мусор.

JVM Spe c может сказать следующее о разгрузке классов

Реализация языка программирования Java может выгружать классы.

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

Классы и интерфейсы, загруженные загрузчиком bootstrap, не могут быть выгружены.

В практическом классе выгрузка почти (я сказал почти) никогда не происходит, так что да, объекты-компаньоны останутся в памяти для жизненного цикла приложения .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...