Javaごみ回収メカニズムの詳細とインスタンスコード

3234 ワード

Javaごみ回収メカニズムの詳細
一見すると、ごみの回収はその名の通り――ごみを探して除去しなければならない.実は正反対です.ゴミ回収は、まだ使用されているすべてのオブジェクトを追跡し、残りのオブジェクトをゴミとしてマークします.この点を覚えてから、「ゴミ回収」と呼ばれる自動メモリ回収がJVMでどのように実現されているのかを深く理解します.
メモリの手動管理
現代版のゴミ回収を紹介する前に、手動でメモリを明示的に割り当て、解放する必要がある日を簡単に振り返ってみましょう.メモリを解放するのを忘れた場合は、このメモリは再利用できません.このメモリは占有されているが使用されていない.このようなシーンはメモリ漏洩と呼ばれています.
次に、Cで書かれた手動でメモリを管理する簡単な例を示します.

int send_request() {
  size_t n = read_size();
  int *elements = malloc(n * sizeof(int));

  if(read_elements(n, elements) < n) {
    // elements not freed!
    return -1;
  }

  // …

  free(elements)
  return 0;
}


メモリの解放を忘れがちになります.メモリの漏洩はかつて非常に一般的な問題だった.自分のコードを絶えず修復することで、それらと抗争するしかありません.したがって、不要なメモリを自動的に解放し、人為的なエラーの可能性を低減するために、より優雅な方法が必要である.この自動化プロセスはゴミ回収(GCと略称)とも呼ばれる.
インテリジェントポインタ
自動ごみ回収の初期の1つの実現は参照カウントである.各オブジェクトが何回引用されているか知っていますが、カウンタが0に戻ると、このオブジェクトは安全に回収されます.C++の共有ポインタは非常に有名な例です.

int send_request() {
  size_t n = read_size();
  stared_ptr> elements 
       = make_shared>();

  if(read_elements(n, elements) < n) {
    return -1;
  }

  return 0;
}


私たちが使用しているsharedptrは、このオブジェクトが参照された回数を記録します.他の人に渡すとカウントが1つ増え、役割ドメインを離れると1つ減ります.このカウントが0になるとsharedptrは、下位レベルの対応するvectorを自動的に削除します.もちろんこれは例にすぎません.読者が指摘しているので、これは現実的には起こり得ませんが、プレゼンテーションとしては十分です.
自動メモリ管理
上記のC++コードでは、メモリ管理が必要であることを明示的に宣言する必要があります.もしすべてのオブジェクトがこのメカニズムを採用したらどうなりますか?それはとても便利で、開発者はメモリの整理を考える必要はありません.実行時にどのメモリが使用されなくなったかを自動的に認識し、解放します.つまり、これらのゴミを自動的に回収します.初代のごみ回収器は1959年にLispが導入したもので,この技術はこれまで進化してきた.
参照数
さっきC++の共有ポインタで実証したアイデアはすべてのオブジェクトに適用できます.多くの言語、例えばPerl、Python、PHPは、このような方法を採用しています.これは1枚の図で簡単に説明できます.
緑のクラウドは、プログラムでまだ使用されているオブジェクトを表します.技術的に言えば、これは実行中のある方法の局所変数、あるいは静的変数のようなものです.プログラミング言語によって状況が異なる可能性がありますので、これは私たちが注目しているポイントではありません.
青い円はメモリ内のオブジェクトを表し、どのくらいのオブジェクトが参照されているかを示します.灰色の円のオブジェクトはもう誰も引用していません.そのため、それらはごみの対象に属して、ごみの回収器によって片付けることができます.
よさそうですね.そうですが、ここには重大な欠陥があります.孤立したループが発生しやすく、オブジェクトはドメイン内にありませんが、互いに参照し合っているため、参照数は0ではありません.次に例を示します.
見たでしょう、赤い部分は実はアプリケーションが使わなくなったゴミの対象です.リファレンスカウントの欠陥のため、メモリの漏洩が発生します.
この問題を解決するには、特殊な「弱い」参照を使用するか、特殊なアルゴリズムを使用してループ参照を回収するなど、いくつかの方法があります.前に述べたPerl,Python,PHPなどの言語は,同様の方法でループリファレンスを回収しているが,これは本明細書で述べる範囲を超えている.JVMで使用される方法について詳しく説明します.
タグ削除
まず、JVMのオブジェクトの達成性の定義を明確にします.前のように緑の雲で曖昧になるのではなく、非常に明確で具体的なゴミ回収ルートオブジェクト(Garbage Collection Roots)の定義があります.
  • ローカル変数
  • アクティブスレッド
  • 静的フィールド
  • JNI参照
  • その他(後述)
  • JVMは、削除されたアルゴリズムをマークすることによって、すべての到達可能(生存可能)オブジェクトを記録し、到達不可能なメモリが再利用されることを保証します.これには、次の2つのステップがあります.
  • タグは、到達可能なすべてのオブジェクトを巡回し、ローカルメモリに記録する情報
  • を指す.
  • 削除すると、オブジェクトに到達できないメモリアドレスが次のメモリ割り当てで使用できるようになります.

  • JVMの異なるGCアルゴリズム、例えばParallel Scavenge、Parallel Mark+Copy、CMSはこのアルゴリズムの異なる実装であり、各段階が少し異なるだけで、概念的には上述した2つのステップに対応している.
    この実装で最も重要なのは、漏洩の対象リングが二度と現れないことです.
    欠点は、アプリケーションのスレッドが回収を完了するために一時停止される必要があることです.参照がずっと変わっているとカウントできません.このアプリケーションは、JVMが家事を片付けることができるように一時停止された場合、Stop The World pause(STW)とも呼ばれます.このような一時停止がトリガーされる可能性は多いが、ごみ回収は最も一般的なものであるはずだ.
    読書に感謝して、みんなを助けることができることを望んで、みんなの当駅に対する支持に感謝します!