17

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

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

Javaのガベージコレクターに頼る以外にメモリ管理を行う方法はありますか?
メモリの管理に役立つ何らかのプログラミング手法で質問に答えるつもりなら、そうしてください。

4

10 に答える 10

16

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

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

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

于 2012-12-13T07:36:26.783 に答える
16

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().

お役に立てれば。

于 2012-12-13T07:38:54.187 に答える
7

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

これまで、メモリー管理を実装する際に Java で GC を回避するための努力が行われてきました ( Real-time Specification for Java (RTSJ) を参照)。これらの取り組みは主に、パフォーマンスのオーバーヘッドや GC に起因する遅延のために、GC が適していない Java でのリアルタイムおよび組み込みプログラミングに専念していました。

RTSJの特徴

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

RTSJ の利点:

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

RTSJ が失敗した/大きな影響を与えなかった理由:

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

Scoped Memory のコード例 ( An Example of Scoped Memory Usageから取得):

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


}
}

ここでは、呼び出された ScopedMemory 実装LTMemoryが事前に割り当てられています。次に、スレッドがスコープ メモリに入り、計算中にのみ必要な一時データを割り当てます。計算の終了後、スレッドは特定の ScopedMemory の内容全体をすぐに空にするスコープ メモリを離れます。遅延は発生せず、予測可能な時間などの一定時間で実行され、GC はトリガーされません。

于 2012-12-13T21:41:40.333 に答える
4

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

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

于 2012-12-13T07:50:47.340 に答える
4

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

このトピックで焦点を当てたいのは、ユース ケースに適した方法で構成することです。JVMチューニングオプションを確認/理解すると役立つかもしれません: http://docs.oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm

于 2012-12-13T07:35:56.903 に答える
3

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

標準的なベスト プラクティスは、正当な理由がない限り、そのような再利用を行わないことです (つまり、プロファイリングを行い、割り当て + GC が問題であり、オブジェクトを再利用するとその問題が解決することを確認しました)。これはより複雑なコードにつながります。間違ったコードを作成すると、実際には GC の仕事が難しくなります (GC がオブジェクトを追跡する方法のため)。

于 2012-12-13T07:35:30.103 に答える
3

Java の基本的な考え方は、"new" を使用して新しいオブジェクトを割り当て、それらを使い終わったときにオブジェクトへの参照が残らないようにする以外は、メモリを扱うべきではないということです。

残りはすべて意図的に Java ランタイムに委ねられ、JVM 設計者が効率よく実行できるように、可能な限りあいまいに定義されています。

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

明確で単純なコードを書くことに集中し、オブジェクトが適切に処理されるようにする必要があります。これにより、JVM に可能な限り最高の動作条件が与えられます。

于 2012-12-13T07:35:51.260 に答える