garbage-collectionガーベジコレクションを開始する


備考

ガベージコレクション(GC)は、プログラムによってもはや必要とされないオブジェクトによって占有されるメモリを自動的に再利用する方法です。これは、プログラマがどのオブジェクトを解放してメモリに戻すべきかを明示的に指定する手動メモリ管理とは対照的です。優れたGC戦略は、手動メモリ管理より効率的ですが、ソフトウェアの種類によって異なる場合があります。

ガベージコレクションの主な利点は次のとおりです。

  • プログラマが手動でメモリ管理を行う必要がなくなります。
  • 手動のメモリ管理(例えば、ポインタのダングリング、二重解放、ある種のメモリリークなど)によって発生する特定の困難なバグを回避します。
  • ガベージコレクションを使用する言語は、通常はあまり複雑ではありません。

主な欠点は次のとおりです。

  • ガベージコレクションには手動メモリ管理に比べてオーバーヘッドがあります。
  • 望ましくない瞬間にガベージコレクションがトリガされると、パフォーマンスに影響を与える可能性があります。
  • プログラマは、ガーベジコレクションがいつ行われ、オブジェクトが解放されたかどうかを知ることはできません。

ほとんどの新しいプログラミング言語には、Java、C#、.NET、Ruby、JavaScriptなどのガベージコレクションが組み込まれています。 CやC ++のような古い言語では、ガベージコレクションは利用できませんが、ガベージコレクションはありません。 Modula-3やAdaのようなガベージコレクションと手動メモリ管理の組み合わせを使用できるようにする言語もあります。

ガベージコレクションの戦略は異なりますが、多くの場合、マークアンドスイープ手法を使用しています。マークフェーズでは、すべてのアクセシブルオブジェクトが検出され、マークされます。掃引フェーズでは、ヒープはアクセスできないマークのないオブジェクトがスキャンされ、次にクリーンアップされます。最新のガベージコレクタは、2つ以上のオブジェクト割り当て領域(世代)が保持される世代別アプローチも使用します。最も若い世代には、割り当てられた最新のオブジェクトが含まれ、より頻繁にクリーンアップされます。特定のタイムスパンで「生き残る」オブジェクトは、古い世代に昇格されます。

GCを使用している多くの言語では、プログラマが微調整することができます( Java 8仮想マシンガベージコレクションチューニングガイドまたは.Netガベージコレクションのドキュメントを参照)

Javaで詳細なGCログを有効にする

通常、jvmのガベージコレクション(gc)は、ユーザ(開発者/エンジニア)にとって透過的です。

ユーザーがメモリリークに直面したり、大量のメモリを必要とするアプリケーションがなければ、GCチューニングは通常必要ではありません。どちらもメモリ不足例外を引き起こし、ユーザーに問題を調査させます。

最初のステップは、通常、実行時のロードまたはアプリケーションの基本ライブラリのサイズが大きいか、クラスローディングまたはスレッドにリークがあるかによって、ヒープまたはパーマネント/メタスペースのいずれかを増やすことです処理メカニズム)。しかし、それが実現可能でないときは、次のステップは何がうまくいかないのかを理解しようとすることです。

特定の瞬間にスナップショットだけが必要な場合は、jdkの一部であるjstat ユーティリティで十分です。

しかし、より詳細な理解のために、各gcイベントの前後にヒープのスナップショットを含むログを持つと便利です。そのためには、 -verbose:gc をjvm起動パラメータの一部として使用し、 -XX:+PrintGCDetails-XX:+PrintGCTimeStamp フラグを含めて、詳細なgcログを有効にする必要があり-verbose:gc

彼らのアプリケーションをプロアクティブにプロファイルしたい人には、 jvisualvm ようなツールもありますjvisualvm は、アプリケーションの動作を把握するためのjdkの一部です。

以下にサンプルプログラム、gc設定、verbose-gcログ出力を示します。

package com.example.so.docs.gc.logging;

import java.util.Arrays;
import java.util.Random;

public class HelloWorld {

    public static void main(String[] args) {
        sortTest();
    }
    
    private static void sortTest() {
        System.out.println("HelloWorld");
        
        int count = 3;
        while(count-- > 0) {
            int size = 1024*1024;
            int[] numbers = new int[size];
            Random random = new Random();
            for(int i=0;i<size;i++) {
                numbers[i] = random.nextInt(size);
            }
            
            Arrays.sort(numbers);
        }
        System.out.println("Done");
        
    }
    

}
 

GCオプション:

-server -verbose:gc  -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  -Xmx10m  -XX:-PrintTenuringDistribution  -XX:MaxGCPauseMillis=250 -Xloggc:/path/to/logs/verbose_gc.log
 

出力:

Java HotSpot(TM) 64-Bit Server VM (25.72-b15) for windows-amd64 JRE (1.8.0_72-b15), built on Dec 22 2015 19:16:16 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 6084464k(2584100k free), swap 8130628k(3993460k free)
CommandLine flags: -XX:InitialHeapSize=10485760 -XX:MaxGCPauseMillis=250 -XX:MaxHeapSize=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-PrintTenuringDistribution -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
0.398: [GC (Allocation Failure) [PSYoungGen: 483K->432K(2560K)] 4579K->4536K(9728K), 0.0012569 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.400: [GC (Allocation Failure) [PSYoungGen: 432K->336K(2560K)] 4536K->4440K(9728K), 0.0008121 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.401: [Full GC (Allocation Failure) [PSYoungGen: 336K->0K(2560K)] [ParOldGen: 4104K->294K(5632K)] 4440K->294K(8192K), [Metaspace: 2616K->2616K(1056768K)], 0.0056202 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
0.555: [GC (Allocation Failure) [PSYoungGen: 41K->0K(2560K)] 4431K->4390K(9728K), 0.0004678 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.555: [GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 4390K->4390K(9728K), 0.0003490 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.556: [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 4390K->293K(5632K)] 4390K->293K(8192K), [Metaspace: 2619K->2619K(1056768K)], 0.0060187 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 2560K, used 82K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 4% used [0x00000000ffd00000,0x00000000ffd14938,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 5632K, used 4389K [0x00000000ff600000, 0x00000000ffb80000, 0x00000000ffd00000)
  object space 5632K, 77% used [0x00000000ff600000,0x00000000ffa49670,0x00000000ffb80000)
 Metaspace       used 2625K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 282K, capacity 386K, committed 512K, reserved 1048576K
 

以下はGC上の便利なリンクです:

  1. gcの概念を説明するアーカイブされたページ(jdk7)
  2. G1コレクターチュートリアル
  3. 便利なVMオプション
  4. JDK 5 - GC人間工学(コンセプトはまだ関連しています)
  5. JDK 6のチューニング(コンセプトはまだ関連しています)

前書き

プログラム内のメインエントリポイントによって到達できなくなったオブジェクトは、ガベージコレクション(GC)の対象となります。 GCは、通常、ユーザーが明示的に実行するのではなく、開発者がオブジェクトが不要になったことをGCに知らせるために、

省略/割り当てnull

someFunction {
     var a = 1;
     var b = 2;
     a = null; // GC can now free the memory used for variable a
     ...
} // local variable b not dereferenced but will be subject to GC when function ends
 

弱参照を使用する

GCを使用するほとんどの言語では、GCの参照としてカウントされないオブジェクトへの弱い参照を作成できます。オブジェクトへの弱い参照のみが存在し、強い(通常の)参照がない場合、オブジェクトはGCに適格です。

WeakReference wr = new WeakReference(createSomeObject());
 

このコードの後で、オブジェクトがまだ存在するかどうかチェックせずに弱参照のターゲットを使用することは危険です。初心者プログラマは、次のようなコードを間違えることがあります。

if wr.target is not null {
    doSomeAction(wr.target);
}
 

これは、GCがヌルチェックの後でdoSomeActionの実行前に呼び出された可能性があるため、問題を引き起こす可能性があります。最初に、次のようなオブジェクトへの(一時的な)強力な参照を作成する方が良いでしょう:

Object strongRef = wr.target;
if strongRef is not null {
    doSomeAction(strongRef);
}
strongRef = null;