web-dev-qa-db-ja.com

理解Javaメモリ管理

Javaプログラマーは、JVMがガベージコレクターを実行することを知っています。System.gc()は、ガベージコレクターを実行するためのJVMへの提案にすぎません。 System.gc()を使用すると、GCがすぐに実行されるとは限りません。

Javaのガベージコレクターを誤解した場合は訂正してください。

Javaのガベージコレクターに依存する以外に、メモリ管理を行う他の方法はありますか?
メモリの管理に役立つ、ある種のプログラミング実践によって質問に回答するつもりなら、そうしてください。

14

Javaメモリ管理について覚えておくべき最も重要なことは、参照を「無効にする」ことです。

参照されていないオブジェクトのみがガベージコレクションの対象になります。

たとえば、次のコードのオブジェクトは収集されず、何もしないためにメモリがいっぱいになります。

_List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) objs.add(new Object());_

しかし、これらのオブジェクトを参照しない場合は、メモリの問題なしに好きなだけループできます。

_List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) new Object();_

したがって、何をするにしても、オブジェクトへの参照を削除して、もう使用しないようにしてください(nullへの参照を設定するか、コレクションをクリアします)。

ガベージコレクターをいつ実行するかは、JVMに任せるのが最善です。まあ、プログラムがメモリを大量に使用し、速度が重要なものに取り掛かる場合を除いて、ガベージコレクションと余分なメモリが発生する可能性があるため、JVMを実行する前にGCを実行することをお勧めします。そうでなければ、個人的にはSystem.gc()を実行する理由はないと思います。

この助けを願っています。

15
NawaMan

以下は、私が昔に書いた小さな要約です(私はいくつかのブログからそれを盗みましたが、どこから来たのか思い出せません-参照なし、申し訳ありません)

  1. Javaでガベージコレクションを行う手動の方法はありません。
  2. Javaヒープは、ガベージコレクションのために3世代に分かれています。これらは、若い世代、退職または古い世代、およびPermエリアです。
  3. 新しいオブジェクトは若い世代で作成され、その後古い世代に移動されます。
  4. 文字列プールはヒープのPerm領域に作成されます。ガベージコレクションはPermスペースで発生する可能性がありますが、JVMによって異なります。
  5. マイナーガベージコレクションは、オブジェクトをエデンスペースからサバイバー1およびサバイバー2スペースに移動するために使用され、メジャーコレクションは、オブジェクトを若い世代から古い世代に移動するために使用されます。
  6. アプリケーションでメジャーガベージコレクションが発生すると、スレッドはその期間停止し、アプリケーションのパフォーマンスとスループットが低下します。
  7. Java 6)のガベージコレクションに適用されているパフォーマンスの向上はほとんどなく、アプリケーションの実行には通常JRE 1.6.20を使用します。
  8. JVMコマンドラインオプション-Xmsおよび-Xmxは、Javaヒープの開始サイズと最大サイズを設定するために使用されます。このパラメーターの理想的な比率は、私の経験に基づいて1:1または1:1.5です。たとえば、両方とも –Xmxおよび–Xms 1GBまたは–Xms 1.2 GBおよび1.8 GB。

コマンドラインオプション:-Xms:<min size> -Xmx:<max size>

14
aviad

ディスカッションに追加するだけです:ガベージコレクションはJavaのメモリ管理の唯一の形式ではありません

過去には、メモリ管理を実装するときに、JavaでGCを回避するための努力が行われてきました( リアルタイム仕様Java( RTSJ) )。これらの取り組みは主に、リアルタイムの埋め込みプログラミングにJavaパフォーマンスオーバーヘッドまたはGCに起因するレイテンシのために、GCが適していなかったJava $ ===)に捧げられました。

RTSJの特性

  • 不滅のスコープメモリ管理-例については、以下を参照してください。
  • GCとImmortal/Scoped Memoryは1つのアプリケーションと共存できます
  • RTSJには、特別に変更されたJVMが必要です。

RTSJの利点:

  • 低レイテンシ、GC一時停止なし
  • リアルタイムのシステム要件を満たすことができる予測可能なパフォーマンスを提供します

RTSJが失敗した理由/大きな影響はありませんでした:

  • スコープ付きメモリの概念は、プログラミングが難しく、エラーが発生しやすく、習得が困難です。
  • リアルタイムGCアルゴリズムの進歩により、ほとんどのリアルタイムアプリでRTSJに代わってリアルタイムGCが使用されるように、GCの一時停止時間が短縮されました。ただし、Scoped Memoriesは、レイテンシが許容されない場所で引き続き使用されます。

スコープ付きメモリのコード例(スコープ付きメモリの使用例= からの引用 ):

import javax.realtime.*;
public class ScopedMemoryExample{

    private LTMemory myMem;

    public ScopedMemoryExample(int Size) {

       // initialize memory
       myMem = new LTMemory(1000, 5000); 
    }

public void periodicTask() {

  while (true)) {
    myMem.enter(new Runnable() {
        public void run() {
          // do some work in the SCOPED MEMORY
          new Object();
          ...
          // end of the enter() method, the scoped Memory is emptied.  
        }
    });
  }


}
}

ここでは、LTMemoryというScopedMemory実装が事前に割り当てられています。次に、スレッドはスコープメモリに入り、計算時にのみ必要な一時データを割り当てます。計算の終了後、スレッドはスコープメモリを離れ、特定のScopedMemoryのコンテンツ全体がすぐに空になります。レイテンシは導入されず、一定の時間で実行されます。予測可能な時間、GCはトリガーされません。

7
Aleš

Javaを使用している場合は、ガベージコレクションを回避できません。多分、あいまいなJVM実装がいくつかあるかもしれませんが、私は知りません。

適切に調整されたJVMは、スムーズに動作するためにSystem.gc()ヒントを必要としないはずです。必要となる正確なチューニングは、アプリケーションの動作に大きく依存しますが、私の経験では、次のフラグを使用して、コンカレントマークアンドスイープオプションを常にオンにしています:-XX:+UseConcMarkSweepGC。このフラグにより​​、JVMはCPUの追加コアを利用して、バックグラウンドスレッドのデッドメモリをクリーンアップできます。これは、ガベージコレクションを実行するときにプログラムが強制的に一時停止される時間を大幅に削減するのに役立ちます。

4
cambecc

私の経験から、Javaでは、JVM自体によって提供されるメモリ管理に依存する必要があります。

このトピックで焦点を当てるのは、ユースケースに受け入れられる方法で構成することです。たぶん、JVMチューニングオプションをチェック/理解すると便利でしょう: http://docs.Oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm

4
Peter Butkovic

System.gc()はコンパイラへのリクエストであり、コマンドではないというのは正しいことです。しかし、以下のプログラムを使用すると、それが発生することを確認できます。

import Java.lang.ref.WeakReference;

public class GCRun {

    public static void main(String[] args) {

        String str = new String("TEMP");
        WeakReference<String> wr = new WeakReference<String>(str);
        str = null;
        String temp = wr.get();
        System.out.println("temp -- " + temp);
        while(wr.get() != null) {
            System.gc();
        }
    }
}
3
Ishan Aggarwal

まあ、GCは常に存在します-ネイティブの呼び出しを使用したり、直接バイトバッファーを割り当てたりしない限り、把握できないオブジェクトを作成することはできませんが、後者の場合、実際にはオブジェクトがなく、ただの束ですバイト)。つまり、オブジェクトを再利用することで、GCを回避することは間違いなく可能です。たとえば、ArrayListオブジェクトの束が必要な場合は、必要に応じてそれぞれを作成し、GCにメモリ管理を処理させることができます。または、それが終わった後、それぞれについてlist.clear()を呼び出して、他の誰かがそれを使用できるキューに置くこともできます。

標準的なベストプラクティスはnotですが、十分な理由がない限り(つまり、割り当てとGCが問題であり、オブジェクトを再利用することで問題が修正されることをプロファイルして確認した場合を除き)、このような再利用を行います。 。それはより複雑なコードにつながり、あなたがそれを間違えた場合、GCが実際に(GCがオブジェクトを追跡する方法のために)仕事を難しくする可能性があります。

3
yshavit

基本的にJava=の考え方は、「新規」を使用して新しいオブジェクトを割り当て、それを使い終わったときにオブジェクトへの参照が残っていないことを確認する以外は、メモリを処理しないことです。

残りはすべて、意図的にJavaランタイムに任せられ、また、意図的に-できるだけ漠然と定義されて、JVM設計者が効率的に実行するための最も自由なものになります。

類推を使用するには:オペレーティングシステムは、ハードディスク領域の名前付き領域(「ファイル」と呼ばれます)を管理します。もう使いたくないエリアの削除と再利用を含みます。そのメカニズムを回避するのではなく、オペレーティングシステムに任せる

明確でシンプルなコードを書くことに集中し、オブジェクトが適切に処理されるようにする必要があります。これにより、JVMは可能な限り最良の動作状態になります。

次のチュートリアルとその内容を確認することをお勧めします

これは、Javaのガベージコレクションの基本について知るための4部構成のチュートリアルシリーズです。

  1. Javaガベージコレクションの紹介

  2. Javaガベージコレクションの仕組み

  3. タイプJavaガベージコレクター

  4. 監視と分析Javaガベージコレクション

私は このチュートリアル がとても役に立ったと感じました。

2
Tasawar Hussain

不要なときに参照を「無効にする」ことが、オブジェクトをガベージコレクションの対象にするための最良の方法です。

オブジェクトをガベージコレクションする方法は4つあります。 1.参照が不要になったら、参照をnullにポイントします。

String s = new String("Java");

この文字列が不要になったら、nullを指すことができます。

s = null;

したがって、sはガベージコレクションの対象になります。

  1. あるオブジェクトを別のオブジェクトに向け、両方の参照が同じオブジェクトを指し、オブジェクトの1つがGCに適格になるようにします。

    文字列s1 = new String( "Java");

    文字列s2 = new String( "C++");

今後、s2もs1を指す必要がある場合、

s1 = s2;

そうすると、「Java」を持つオブジェクトがGCの対象になります。

  1. メソッド内で作成されたすべてのオブジェクトは、メソッドが完了すると、GCの対象になります。したがって、メソッドがスレッドのスタックから破棄されると、そのメソッド内の対応するオブジェクトが破棄されます。

  2. Island of Isolationは、内部リンクがあり、参照への外部リンクがないオブジェクトがガベージコレクションの対象となる別の概念です。 ガベージコレクションの「孤立の島」

例:以下は、AndroidのCameraクラスのメソッドです。開発者がmCameraSourceが不要になったらnullにポイントする方法を確認してください。これはエキスパートレベルのコードです。

public void release() {
        if (mCameraSource != null) {
            mCameraSource.release();
            mCameraSource = null;
        }
    }

ガベージコレクターの仕組み
ガベージコレクションは、ガベージコレクタと呼ばれるデーモンスレッドによって実行されます。その時点で十分なメモリが利用可能な場合、このデーモンスレッドの優先度は低く、バックグラウンドで実行されます。しかし、JVMがヒープがいっぱいであることを検出し、JVMが一部のメモリを再要求する場合、ガベージコレクタスレッドの優先度を上げ、参照またはnull参照を持たないすべてのオブジェクトを検索するRuntime.getRuntime.gc()メソッドを呼び出します。それらのオブジェクトを破棄します。

1
Utsav