コンパニオンオブジェクトはアプリのライフサイクルの間メモリに残りますか


8

Kotlinでは、コンパニオンオブジェクトを使用してシングルトンを作成できます。

class MyClass {
   companion object {
        fun doSomething() {

        }
    }
}

コトリンのドキュメントによると、それは述べています:

コンパニオンオブジェクトのメンバーは他の言語では静的メンバーのように見えますが、実行時にはそれらは実際のオブジェクトのインスタンスメンバーであることに注意してください...

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

これは、コンパニオンオブジェクトで関数を使用した後、クラスのインスタンス(MyClass)がアプリのライフサイクル全体にわたってメモリに残ることを意味しますか?Android Studioでこれが事実かどうかを確認する方法はありますか?


参照したドキュメントへのリンクを提供できますか?
Sonu Sanjeev

リンクを投稿に追加しました。
AndroidDev

回答:


6

クラスのインスタンス(MyClass)は、アプリのライフサイクル全体にわたってメモリに残りますか?

JVMのコンパニオンオブジェクト

コトリンで

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

上記のコードのように、JVMではクラスcompanion objectとして宣言され、Companionクラスstatic内のフィールドとして作成されますMyClass。したがって、gcによって収集されません。したがって、オブジェクト(コンパニオン)のメモリはの間も残りProcessLifecycleます。static final object通常はリリースされません。

結論として、MyClass.Companionアプリケーションでインスタンスを参照した場合、そのインスタンスはガベージコレクションされません。(一般的なクラスローダー)。

* MyClass.Companionアプリケーションでインスタンスを参照していない場合、コード圧縮機能によって削除される可能性があります。

Android Studioでこれが事実かどうかを確認する方法はありますか?

android studio>プロファイラ>ヒープダンプで確認できます

参照


いい答えだ!しかし、「JVMに変換されたMyClass(Kotlin)」コードをどのようにして見つけましたか?
Astha

0

ご存知のように、上記の回答は、コンパニオンオブジェクトがクラスに変換され、それらを宣言するクラスがコンパニオンクラスのオブジェクトへの静的参照を保持していることも明らかにしています。

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

今問題

コンパニオンオブジェクトはアプリのライフサイクルの間メモリに残りますか

宣言クラスがstaticコンパニオンクラスへの参照を保持しているため、質問staticはjvm のフィールドの存続期間に短縮され、class答えはJVM仕様にありますが、仕様は説明が少々乾燥しているため、内部の本からいくつかのスニペットを追加していますJava仮想マシン

あなたの例のようにclass、1つのコンパニオンオブジェクトだけを持っているとします。

最初の質問は、いつコンパニオンクラスのオブジェクトが作成されるかです。 またはstaticフィールドが初期化されるとき?

関連するテキストブック。(コンテキストの本はクラスのロード手順について話している)

初期化

最初のアクティブな使用のためにクラスまたはインターフェースを準備するために必要な最後のステップは、初期化、つまりクラス変数を適切な初期値に設定するプロセスです。ここで使用する「適切な」初期値とは、クラス変数に対してプログラマーが希望する開始値です。適切な初期値は、準備中にクラス変数に与えられるデフォルトの初期値と対照的です。上記のように、仮想マシンは各変数のタイプのみに基づいてデフォルト値を割り当てます。対照的に、適切な初期値は、プログラマーだけが知っているいくつかのマスタープランに基づいています。Javaコードでは、クラス変数初期化子または静的初期化子を介して適切な初期値が指定されています。

したがってMyClass、ロードして初期化すると、コンパニオンクラスのオブジェクトが作成されることがわかります。

しかし、JVMがロードされる原因は何MyClassですか?

Java Virtual Machine仕様は、クラスとインターフェースのロードおよびリンクのタイミングに実装の柔軟性を提供しますが、初期化のタイミングを厳密に定義します。すべての実装は、最初のアクティブな使用時に各クラスとインターフェイスを初期化する必要があります。クラスのアクティブな使用法は次のとおりです。

  1. クラスの新しいインスタンスでのコンストラクターの呼び出し

  2. クラスを要素型とする配列の作成

  3. クラスによって宣言されたメソッドの呼び出し(スーパークラスから継承されていない)

4クラスによって宣言されたフィールドの使用または割り当て(スーパークラスまたはスーパーインターフェースから継承されない)。ただし、静的で最終的なフィールドであり、コンパイル時の定数式によって初期化されるフィールドを除く

したがって、4番目のポイントのようにMyClass.foo()、kotlinから実行するかMyClass.Companion.foo()、この時点MyClassでロードされ、準備が整います。(おそらくかなり早い)

この時点ではオブジェクトはMyClass存在しないことに注意してください。つまり、式は使用していませんMyClass()

これはstatic、アプリケーションが実行されている限り、フィールドがメモリに残ることを意味しますか?

宣言型がアンロードMyClassされると、ガベージコレクションされる可能性があります。この場合、JVMまたはART(androidの場合)がアンロードされると、コンパニオンオブジェクトがガベージコレクションされる可能性があります。

JVM Specはクラスのアンロードについて次のように述べています

Javaプログラミング言語の実装により、クラスがアンロードされる場合があります。

§12.6で説明されているように、ガベージコレクターがその定義クラスローダーを再利用できる場合に限り、クラスまたはインターフェースをアンロードできます。

ブートストラップローダーによってロードされたクラスとインターフェースは、アンロードされない場合があります。

実用的なクラスでは、アンロードはほとんど(ほとんど言っていませんが)発生しないのでコンパニオンオブジェクトはアプリのライフサイクルの間メモリに残ります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.