未来エンジニア養成所Blog

プログラミングを皆に楽しんでもらうための情報をお届けします。

【Java】ガベージコレクション

title


ガベージコレクション機能

ガベージコレクションとは、Javaのメモリ管理を自動的に行ってくれるもので、外部からの参照がなくなったオブジェクトをJavaVMが削除してくれる機能です。

C言語などは使ったメモリを解放するために、明示的にプログラムを書く必要があります。

このメモリの解放処理を忘れると、使用可能なメモリ領域が少なくなり、システムが止まってしまうことがあります。


Javaではこのメモリ管理をガベージコレクションが自動的に行ってくれるため、プログラミングが楽になります。

ガベージコレクションの実行はJavaVMが行います。

したがってプログラマは実行を強制することができません。

プログラマは参照する変数にnullを代入して、参照していないことをJavaVMに通知したり、System.gc();を記述してメモリを解放してほしいことをプログラミングするだけで、実行してくれるJavaVMに実行を促すことしかできません。

このようなJavaVMにガベージコレクションを発動してほしいとプログラミングすることを「ガベージコレクションの対象にする」と言います。


これまでのプログラミングを思い出してください。

Humanのインスタンスtaroを作っても、String型のインスタンスを作ってもメモリ解放処理を記述しませんでした。

オブジェクトは、通常、そのオブジェクトが作成された{}ブロック内で有効であるため、ブロックが終了すると、自動的にJavaVMによって解放されるようになっています。


オブジェクトをガベージコレクションの対象とする

オブジェクトはどこからか参照されている間は、ガベージコレクションの対象となりません。

ガベージコレクションの対象となるという状態は、どこからも参照されていない状態である、ということです。

この状態になるには、前述したようにオブジェクトが生成されたブロックが終了するとガベージコレクションによりメモリ解放が行われます。

プログラムで明示的にガベージコレクションの対象にするには、次の2通りがあります。

  • オブジェクトを参照している変数にnullを代入する
  • 参照している変数を他のオブジェクトに割り当てる(他のオブジェクトを参照させる)


また、オブジェクトが参照しあっている場合でも、外部からの参照がなくなるとガベージコレクションになります。


【オブジェクトをガベージコレクションの対象にする1】

public class GcSample {
    public static void main(String[] args) {
        MyObj obj = new MyObj();
        MyObj obj2 = obj;
        obj = new MyObj();
        obj2 = obj;
        obj2 = new MyObj();
    }
}


GcSampleクラスを実行してもコンソールには何も出力しませんが、ここではMyObjクラスから生成されたインスタンスがどのようなタイミングでガベージコレクションの対象になるかを見ておきます。

ex1

ここでは、インスタンスが生成された場所(参照値)を仮に100番地、200番地、300番地と呼ぶことにします。


3行目ではMyObjクラスのインスタンスを100番地に生成して100番地という参照値を変数obj1に格納しています。

4行目では、変数objがもっている参照値100番地を、変数obj2に代入しています。

これにより変数objとobj2はどちらも100番地を参照していることになります。

5行目ではMyObjクラスの新たなインスタンスを生成し(仮に200番地とします)変数objに代入しています。

この時点で変数objは200番地、変数obj2は100番地を参照しています。

6行目では変数obj2にはobjの参照値が代入されているので、200番地を参照するようになります。


この6行目がおわった時点で100番地のオブジェクトは変数objからもobj2からも参照されず、ガベージコレクションの対象になります。

7行目では、またあらたなMyObjクラスがインスタンス化され、変数obj2に代入をしています。(仮に300番地)

この時点で、変数objは200番地、obj2は300番地を参照していることになります。


7行目が終わった段階では、200番地と300番地はまだそれぞれ参照されているので、ガベージコレクションの対象にはなりませんが、8行目でmain()メソッドが終了したタイミングで、main()メソッドのスコープが終了し、すべての参照がガベージコレクションの対象となります。


【オブジェクトをガベージコレクションの対象にする2】

public class GcSample2 {
    GcSample2 obj;
    public static void main(String[] args) {
        GcSample2 obj2 = new GcSample2();
        GcSample2 obj3 = new GcSample2();
        GcSample2 obj4 = new GcSample2();

        obj2.obj = obj3;
        obj3.obj = obj4;
        obj4.obj = obj2;

        obj2 = null;
        obj3 = null;
        obj4 = null;

        //これ以降3つのオブジェクトに外部からアクセスすることはできない
    }
}


GcSample2クラスには、2行目で参照変数objが定義されています。

これにより4行目~6行目のようにGcSample2クラスをインスタンス化すると、obj2、obj3、obj4のそれぞれのオブジェクトに参照変数objが生成されます。

8行目でobj2オブジェクトが持っている変数objにobj3の参照を代入しています。

同様に、obj3オブジェクトのobjはobj4を参照し、obj4オブジェクトのobjはobj2を参照しています。

つまりそれぞれのインスタンス間で参照をしあっていることになります。

12行目~14行目でobj2、obj3、obj4にnullを代入することによって、それぞれの変数からの参照はなくなります。

ところが、obj2の中のobjはまだobj3を参照しており、obj3の中のobjはobj4を参照していて、まったく参照されない状態にはなっていません。


このようにオブジェクト同士がまだ参照し合っていても、外部からの参照がなくなってしまったら、この3つのオブジェクトを使うことはできないので、14行目が終わった時点で、ガベージコレクションの対象になります。

ex2


finalize()メソッド

Objectクラスに定義されているfinalize()メソッドはオブジェクトが破棄される寸前に自動的に呼び出されるメソッドです。

ガベージコレクションの実行はJavaVMにゆだねられているので、finalize()メソッド呼び出しの厳密なタイミングはわかりません。

また複数のオブジェクトのfinalize()がどのような順番で実行されるかもわかりません。

しかし、Objectクラスに定義されたこのメソッドは、中身が何も記述されていないので、サブクラスでオーバーライドすることで、オブジェクトが破棄するタイミングで何らかの処理を実行させることができます。

finalize()メソッドを呼び出すには、「System.gc();」と記述します。


【finalizeメソッドの利用】
MyObj2クラス

public class MyObj2{
    public void finalize( ){
        System.out.println("インスタンスが解放されます");
    }
}


GCSample3クラス

public class GCSample3{
    public static void main(String[ ] args){
        MyObj2 obj = new MyObj2( );
        MyObj2 obj2 = obj;

        System.out.println("GCを呼び出します 1");
        System.gc( );

        obj = null;

        System.out.println("GCを呼び出します 2");
        System.gc( );

        obj2 = null;

        System.out.println("GCを呼び出します 3");
        System.gc( );

        System.out.println("mainを終了します");
    }
}

実行結果

GCを呼び出します 1
GCを呼び出します 2
GCを呼び出します 3
mainを終了します
インスタンスが解放されます


ここでは、1つのインスタンスに2つの参照objとobj2があります。

両方の参照をnullにするとGCの対象になるため(14行目)、そのあとGCが実行されていることによりインスタンスが解放されています。

これはfinalize( )メソッドが呼ばれている事で、GCが実行されている事がわかります。


ここで注意が必要です。

System.gc( )メソッドを呼び出してもGCが実行される保証はありません。

GCはJavaVMによって実行されますが、System.gc( )メソッドはGCの実行を依頼するのみで、GCを実行するかどうかはJavaVMの動作次第になるからです。


まとめ

  • ガベージコレクション機能

    • 外部から参照されなくなったオブジェクトをJavaVMが解放する機能です。
    • 実行のタイミングを決めるのはJavaVMです。

  • オブジェクトをガベージコレクションの対象にする

    • 参照変数にnullを代入するか、他の参照オブジェクトに参照を割り当てます。

  • finalize()メソッド

    • Objectクラスに定義されたメソッドで、ガベージコレクションがオブジェクトを解放する前に一度だけ実行されます。


参考図書



独学で挫折しそうになったら、オンラインプログラミングスクール
未来エンジニア養成所Logo



あわせて学習したい

phoeducation.work phoeducation.work