Bleiben Begleitobjekte für den Lebenszyklus der App im Speicher?

8

In Kotlin können Sie einen Singleton mithilfe eines Begleitobjekts erstellen:

class MyClass {
   companion object {
        fun doSomething() {

        }
    }
}

Laut den Kotlin-Dokumenten heißt es:

Beachten Sie, dass die Mitglieder von Begleitobjekten, obwohl sie in anderen Sprachen wie statische Elemente aussehen, zur Laufzeit immer noch Instanzmitglieder von realen Objekten sind ...

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

Bedeutet dies, dass nach Verwendung einer Funktion im Begleitobjekt die Instanz der Klasse (MyClass) für den gesamten Lebenszyklus der App im Speicher verbleibt? Gibt es in Android Studio eine Möglichkeit, zu überprüfen, ob dies der Fall ist?

AndroidDev
quelle
Können Sie den Link zu dem Dokument angeben, das Sie empfohlen haben?
Sonu Sanjeev
Verknüpft zum Beitrag hinzugefügt.
AndroidDev

Antworten:

6

Instanz der Klasse (MyClass) bleibt für den gesamten Lebenszyklus der App im Speicher ?

Begleitobjekt in JVM

in Kotlin

class MyClass {
   companion object {
        fun doSomething() {

        }
    }
}

MyClass (Kotlin) wurde in JVM konvertiert

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();
      }
   }
}

Wie oben beschrieben, companion objectwird Code Companionin JVM als Klasse deklariert und als staticFeld innerhalb der MyClassKlasse erstellt. Somit wird nicht von gc gesammelt. So bleibt die Erinnerung an das Objekt (Companion) während des ProcessLifecycle. static final objectwird im Normalfall nicht freigegeben.

Wenn auf eine MyClass.CompanionInstanz in der Anwendung verwiesen wird , wird diese Instanz nicht als Müll gesammelt. (über allgemeine Klassenlader).

* Wenn MyClass.Companionin der Anwendung nicht auf die Instanz verwiesen wird , kann sie durch die Funktion zum Verkleinern des Codes entfernt werden .

Gibt es in Android Studio eine Möglichkeit, zu überprüfen, ob dies der Fall ist?

Sie können durch Android Studio> Profiler> Heap Dump sehen.

Referenz

Ethan Choi
quelle
Gute Antwort! Aber wie haben Sie den in JVM konvertierten Code "MyClass (Kotlin)" gefunden?
Astha
0

Wie Sie zu wissen scheinen und die obige Antwort auch deutlich macht, dass Begleitobjekte in Klassen übersetzt werden und die Klasse, die sie deklariert, einen statischen Verweis auf das Objekt der Begleitklasse enthält, wie folgt:

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

Nun die Frage

Bleiben Begleitobjekte für den Lebenszyklus der App im Speicher?

Da die deklarierende Klasse einen staticVerweis auf die Companion-Klasse enthält, reduziert sich die Frage auf die Lebensdauer der staticFelder in jvm classund die Antwort liegt in der JVM-Spezifikation , aber die Spezifikation ist in der Erklärung etwas trocken, sodass ich einige Ausschnitte aus dem Buch Inside hinzufüge die Java Virtual Machine .

Nehmen wir an, wir haben wie in Ihrem Beispiel ein classObjekt mit nur einem Begleiter.

Die erste Frage ist, wann ein Objekt der Companion-Klasse erstellt wird. oder wenn staticFelder initialisiert werden?

relevanter Text aus dem Buch . (Für den Kontext spricht das Buch über das Laden von Klassen)

Initialisierung

Der letzte Schritt, der erforderlich ist, um eine Klasse oder Schnittstelle für ihre erste aktive Verwendung vorzubereiten, ist die Initialisierung, bei der Klassenvariablen auf ihre richtigen Anfangswerte gesetzt werden. Wie hier verwendet, ist ein "richtiger" Anfangswert der gewünschte Startwert des Programmierers für eine Klassenvariable. Ein korrekter Anfangswert steht im Gegensatz zu dem Standardanfangswert, der Klassenvariablen während der Vorbereitung zugewiesen wird. Wie oben beschrieben, weist die virtuelle Maschine Standardwerte zu, die nur auf dem Typ jeder Variablen basieren. Die richtigen Anfangswerte basieren dagegen auf einem Masterplan, der nur dem Programmierer bekannt ist. In Java-Code wird ein geeigneter Anfangswert über einen Klassenvariablen-Initialisierer oder einen statischen Initialisierer angegeben.

Wir wissen also, dass nach dem MyClassLaden und Initialisieren das Objekt der Companion-Klasse erstellt wird.

aber was würde dazu führen, dass JVM geladen wird MyClass?

Die Java Virtual Machine-Spezifikation bietet Implementierungen Flexibilität beim Timing des Ladens und der Verknüpfung von Klassen und Schnittstellen, definiert jedoch das Timing der Initialisierung streng. Alle Implementierungen müssen jede Klasse und Schnittstelle bei ihrer ersten aktiven Verwendung initialisieren. Eine aktive Nutzung einer Klasse ist:

  1. Der Aufruf eines Konstruktors für eine neue Instanz der Klasse

  2. Die Erstellung eines Arrays, dessen Elementtyp die Klasse ist

  3. Der Aufruf einer von der Klasse deklarierten Methode (nicht von einer Oberklasse geerbt)

4 Die Verwendung oder Zuweisung eines von der Klasse deklarierten Felds (nicht von einer Oberklasse oder Superschnittstelle geerbt), mit Ausnahme von Feldern, die sowohl statisch als auch endgültig sind und durch einen konstanten Ausdruck zur Kompilierungszeit initialisiert werden

Also ab dem 4. Punkt, wenn Sie MyClass.foo()von Kotlin oder MyClass.Companion.foo()an diesem Punkt tun, MyClasswird geladen und bereit. (Wahrscheinlich viel zu früh)

Bitte beachten Sie, dass zu diesem Zeitpunkt kein Objekt MyClassexistiert, dh wir haben keinen Ausdruck verwendet MyClass().

Bedeutet dies, dass staticFelder so lange im Speicher bleiben, wie die Anwendung ausgeführt wird?

Sie können Müll gesammelt werden, wenn der deklarierende Typ entladen wird. In unserem Fall, wenn JVM oder ART (auf Android) entladen werden, MyClassbesteht die Möglichkeit, dass das Begleitobjekt Müll gesammelt wird.

JVM Spec hat Folgendes zum Entladen von Klassen zu sagen

Eine Implementierung der Programmiersprache Java kann Klassen entladen.

Eine Klasse oder Schnittstelle kann genau dann entladen werden, wenn ihr definierender Klassenlader vom Garbage Collector zurückgefordert werden kann, wie in § 12.6 beschrieben.

Vom Bootstrap Loader geladene Klassen und Schnittstellen dürfen nicht entladen werden.

In der praktischen Klasse kommt das Entladen fast (ich sagte fast) nie vor, also bleiben Begleitobjekte für den Lebenszyklus der App im Speicher .

mächtige WOZ
quelle