blog

読書メモ - Java仮想マシンのガベージコレクタとメモリ割り当て戦略

この記事では、Java仮想マシンのガベージコレクタとメモリ割り当て戦略について説明します。 ガベージ・コレクション(GC)というと、多くの人はこの技術をJava言語の仲間だと考えています。実際、GCの...

May 16, 2020 · 24 min. read
シェア

この記事では、Java仮想マシンのガベージコレクタとメモリ割り当て戦略について説明します。

概要

GCガベージコレクション)というと、多くの人はこの技術をJava言語の仲間だと考えています。実際、GCの歴史はJavaよりも古く、1960年にMITで生まれたLispは動的メモリ割り当てとゴミコレクションの技術を実際に使用した最初の言語でした。Lispがまだ胎動していた頃、人々はGCが達成すべき3つのことについて考えていました:

  • 取り戻すべき記憶とは?
  • リコールはいつですか?
  • どのようにリサイクルされているのですか?

一世紀以上の開発の後、動的メモリ割り当てとメモリ再利用の技術はかなり成熟し、すべてが自動化の時代に入ったように見えますが、なぜGCとメモリ割り当てを理解する必要があるのでしょうか?答えは簡単で、様々なメモリオーバーフローやメモリ流出の問題をトラブルシューティングする必要があるときや、システムがより高い並行性を達成するためにゴミ収集がボトルネックになるとき、これらの自動化技術の必要な監視とチューニングを実装する必要があるからです。

時計の針を半世紀戻して現在に戻り、馴染みのあるJava言語に戻ると、Javaメモリの実行時領域にあるプログラム・カウンタJava仮想マシン・スタックローカル・メソッド・スタックはスレッドとともに生きて死にますスタック内のスタック・フレームはメソッドがスタックに入ったり出たりするときに、整然とスタックの入出力を行います。各スタック・フレームにどれだけのメモリが割り当てられるかは、基本的にクラス構造が決定された時点でわかっているため、これらの領域でのメモリ割り当てとメモリ再生成は決定論的であり、メソッドの終了時やスレッドの終了時にメモリは自然に再生成されるため、これらの領域での再生成について深く考える必要はありません。Javaのヒープとメソッド領域は異なりインターフェイスの複数の実装クラスが必要とするメモリは異なる可能性があり、メソッドの複数の分岐が必要とするメモリは異なる可能性があり、どのオブジェクトが作成されるかはプログラムが実行されているときにしかわからないため、メモリのこの部分の割り当てと回収は動的であり、ごみコレクタはメモリのこの部分に焦点を当てます。以下のメモリ割り当てとメモリ回復の議論は、メモリのこの部分にのみ言及しています。

その物体は死んだのですか?

ヒープにはJavaの世界にあるほとんどすべてのオブジェクト・インスタンスが格納されています。ヒープを回収する前にゴミ・コレクターが最初に行うことは、どのオブジェクトがまだ生きていて、どのオブジェクトが死んでいるかを判断することです。

参照カウントアルゴリズム

参照カウンティング・アルゴリズムの概要はオブジェクトに参照カウンターを追加し、それがどこかで参照されるたびにカウンターの値に1を加えるというもの。

客観的に言えば、参照カウントアルゴリズムの実装は、単純かつ効率的ほとんどの場合、それは良いアルゴリズムであり、いくつかの有名なアプリケーションの例、次のようなものがあります:マイクロソフト社のCOM技術、ActionScript 3FlashPlayerの使用Python言語、およびゲームスクリプトの分野で広くリスで使用されています。しかし、少なくとも主流のJava仮想マシンはメモリを管理するための参照カウントアルゴリズムを選択しない主な理由は、それが困難なオブジェクト間の循環参照の問題を解決するためです、例えば:オブジェクトAとオブジェクトBはもはや2つのオブジェクトへの参照を持っていないに加えてお互いへの参照を保持し、実際には、これらの2つのオブジェクトにアクセスすることは不可能であったが、彼らは相互参照のためです。しかし、互いに参照しているため、参照カウントはゼロではないので、参照カウントアルゴリズムはGCコレクタに再要求を通知することはできません

アクセシビリティ分析アルゴリズム

主要な商用プログラミング言語の主流の実装では、オブジェクトは、到達可能性分析によって生きているかどうかを決定されると主張されています。このアルゴリズムの基本的な考え方はGC Roots と呼ばれる一連のオブジェクトを始点とし、これらのノードから下に向かって検索を開始し、検索によって取られる経路を参照チェーンと呼び、GC Rootsオブジェクトが接続されている参照チェーンを持っていない場合、次の図に示すように、オブジェクトが利用できないことが証明されます:

オブジェクト 5オブジェクト 6オブジェクト 7 は互いに関連していますが、GC Rootsには到達できないのでリサイクル可能であると判断されます。

Java言語ではGC Rootとして使用できるオブジェクトには以下のようなものがあります:

  • Java仮想マシン・スタックで参照されるオブジェクト
  • メソッド領域のクラス静的属性によって参照されるオブジェクト
  • メソッド領域の定数によって参照されるオブジェクト
  • ローカル・メソッド・スタックでJNIが参照するオブジェクト

また参照の話

参照カウント・アルゴリズムによってオブジェクトへの参照の数を決定する場合でも、到達可能性解析アルゴリズムによってオブジェクトの参照の連鎖が到達可能かどうかを決定する場合でも、オブジェクトが生きているかどうかを決定することは、参照に関連しています。JDK 1.2以前では、Javaにおける参照の定義は伝統的なものでした。つまり、参照型のデータに格納された値が別のメモリ片の開始アドレスを表す場合、そのメモリ片は参照を表すと言われていました。この定義は非常に純粋ですが、あまりにも狭く、この定義ではオブジェクトが参照されるか、または参照されない2つの状態であり、どのように "無味、廃棄 "オブジェクトのいくつかを記述するために、助けることができないようです。まだ十分なメモリ空間がある場合にはメモリ内に保持しゴミ収集後にメモリ空間が非常にタイトな場合には破棄することができるオブジェクトのクラスを記述することが望ましい。多くのシステムにはこのシナリオに適合するキャッシュ機能があります。

JDK 1.2以降、Javaは参照の概念を拡張し、参照を4つのタイプに分けました:強い参照柔らかい参照弱い参照、そして**仮想参照**で、順番に徐々に弱くなっていきます

  • 強力な参照とは、プログラムコード中に広く存在する参照のことで、例えば Object obj = new Object(); のようなものです。強力な参照がまだ存在する限り、ごみコレクタが参照オブジェクトを回収することはありません。
  • ソフト・リファレンスは、まだ使えるが必須ではないオブジェクトを表すのに使われます。メモリ・オーバーフロー例外が発生しそうなソフト参照に関連付けられたオブジェクトは、2 回目の再利用のためにリストされます。この再利用に十分なメモリがない場合、メモリ・オーバーフロー例外が発生します。JDK 1.2 以降では、ソフト参照を実装するために SoftReference クラスが提供されています。
  • 弱参照も必須でないオブジェクトを表すのに使われますが、ソフト参照より少し弱く、弱参照で関連付けられたオブジェクトは、次のゴミ収集が行われるまでしか生き残りません。ゴミ回収が行われるときには、現在のメモリが十分かどうかに関係なく、弱い参照に関連付けられたオブジェクトだけを回収します。JDK 1.2 以降、弱参照を実装するために WeakReference クラスが提供されています。
  • ダミー参照はゴースト参照やファントム参照とも呼ばれ、最も弱い参照関係です。オブジェクトにダミー参照があってもなくても、そのオブジェクトの生存時間にはまったく影響しませんし、ダミー参照を通じてオブジェクトのインスタンスを取得することもできません。オブジェクトにダミー参照を関連付ける唯一の目的は、オブジェクトがコレクタに回収されたときにシステム通知を受け取れるようにすることです。JDK 1.2 以降、ダミー参照を実装するために PhantomReference クラスが提供されています。

生きるか死ぬか。

オブジェクトが到達可能性分析アルゴリズムで到達不可能であったとしても、それは死ぬ必要はなく、それらは一時的に執行猶予中であり、オブジェクトの死を本当に宣言するためには、少なくとも2つのマーキングプロセスを経なければなりません:オブジェクトが到達可能性分析の後にGCルーツに接続された参照チェーンを持っていないことが判明した場合、それは初めてマークされ、フィルタリング処理を受けフィルタリングはオブジェクトがGCルーツに接続された参照チェーンを持っているかどうかの条件に基づいて行われます。メソッドが必要ですオブジェクトがfinalize()メソッドをオーバーライドしていない場合、またはfinalize()メソッドがすでにVMによって呼び出されている場合VMは両方のケースを不要なものとして扱います。

finalize() メソッドを実行する必要があると判断された場合、オブジェクトはF-Queueと呼ばれるキューに置かれ、仮想マシンによって自動的に作成された優先度の低い Finalizer スレッドが後で実行します。なぜなら、オブジェクトがfinalize()メソッドでゆっくり実行されたり、デッドループが発生したりすると、F-Queue のキューにある他のオブジェクトが永久に待たされたり、メモリ再生システム全体がクラッシュしたりする可能性が非常に高いからです。もしオブジェクトがfinalize()自分自身をうまく保存したいのであれば、クラス変数やオブジェクトのメンバ変数に自分自身を代入するなどして参照チェーンの任意のオブジェクト・レジュームと再び関連付けるだけですクラス変数やオブジェクトのメンバ変数に代入れたオブジェクトは2回目のマークアップでコレクションから削除れます

なぜなら、これはC/C++のデストラクタではなくJavaが最初に作られたときに、C/C++プログラマに受け入れられやすいように妥協して作られたものだからです。実行にはコストがかかり、不確実性が高く、個々のオブジェクトが呼び出される順番も保証されていませんfinalize()は、try-finallyや他の手段を使えば、もっとうまくもっとタイムリーにできる作業をすべてやってしまうのでJava言語にこのメソッドが存在することは、まったく忘れてしまったほうがいいでしょう

リサイクル手法領域

JavaのVM仕様ではVMがメソッド領域にゴミ収集を実装する必要はないかもしれないし、そうする方が一般的に費用対効果が低いと書かれています。ヒープ、特に新しい世代では、通常のアプリケーションによる1回のゴミ収集で一般的に70~95パーセントの領域が回収されますが、パーマネント世代のゴミ収集はこれよりもはるかに効率が悪いのです.

パーマネントジェネレーションのゴミ・コレクションは、非推奨定数と無駄なクラスという2つの主なコンポーネントをリサイクルします。非推奨定数のリサイクルは、Javaのヒープでオブジェクトをリサイクルするのとよく似ています。定数プール内のリテラルの回収を例にとると、文字列abcが定数プールに入ったものの、現在のシステム内にabcというStringオブジェクトがない場合、言い換えれば、定数プール内にabc定数を参照するStringオブジェクトがなく、このリテラルを参照する場所が他にない場合、この時点でメモリ再生成が発生し、必要に応じてabc定数はシステムによって定数プールから削除されます。定数プール内の他のクラスメソッドフィールドへのシンボリック参照も同様です。

ある定数が非推奨定数であるかどうかを判断するのは比較的簡単ですが、あるクラスが無用なクラスであるかどうかを判断する条件はより厳しいものです使い物にならないクラスと判断されるには、以下の3つの条件をすべて満たす必要があります:

  • つまり、Java ヒープにはクラスのインスタンスは存在しません。
  • クラスをロードした ClassLoader がリサイクルされました。
  • このクラスに対応するJava.lang.Classオブジェクトはどこにも参照されず、クラスのメソッドはリフレクションによってどこにもアクセスできません。

仮想マシンは、上記の3つの条件を満たす無用なクラスをリサイクルすることができます。ここでは、オブジェクトのように、使用されなくなったときに必ずしもリサイクルされるとは限らず、単にリサイクルできるという話をしています。クラスがリサイクルされるかどうかは、HotSpot仮想マシンが提供する**-Xnoclassgcパラメータで制御できます-verbose:classと-XX:+TraceClassLoadingは、仮想マシンの製品バージョンで使用できますには、FastDebugバージョンのVM** サポートが必要です。

リフレクション動的プロキシCGLibのようなByteCodeフレームワーク、動的に生成されるJSPOSGiのような頻繁にカスタマイズされるClassLoaderシナリオの広範な使用において、仮想マシンは、永久的な生成がオーバーフローしないことを保証するために、クラス・アンロード機能を持つことが要求されます。

ゴミ収集アルゴリズム

ゴミ収集アルゴリズムの実装には手続き的な詳細が多く含まれ、また仮想マシンのメモリ操作はプラットフォームによって異なるため、この記事ではアルゴリズムの実装について多くを論じることはせず、いくつかのアルゴリズムのアイデアとその開発プロセスを紹介することだけを目的としています。

マーククリアアルゴリズム

最も基本的な回収アルゴリズムはマーキング-クリアリングアルゴリズムで、その名前が示すように、アルゴリズムはマーキングとクリアリングの2つのフェーズに分かれています:まず、リサイクルされるすべてのオブジェクトをマークしマーキングが完了した後、すべてのマークされたオブジェクトの統一された回収マーキングプロセスは、実際には、オブジェクトのマーキング判定の前の説明で紹介しました。これが最も基本的な回収アルゴリズムと言われる理由は、後続の回収アルゴリズムがこの考え方をベースにして、その欠点を改善しているからです。その主な欠点は2つ

  • 効率性の問題採点プロセスも清算プロセスも効率的ではありません
  • スペースの問題マーカーを消去すると、大量の不連続なメモリーの断片化が生じますスペースの断片化が大きすぎると、プログラムの実行時間の後半でより大きなオブジェクトを割り当てる必要が生じ、十分な連続メモリーを見つけることができず、事前に別のゴミ収集アクションをトリガーしなければならなくなる可能性があります。

マーククリアアルゴリズムの実行を以下に示します:

レプリケーション・アルゴリズム

この効率性の問題を解決するために、レプリケーションと呼ばれる収集アルゴリズムが導入され、利用可能なメモリーを容量に応じて2つの同じ大きさのチャンクに分割し、一度に片方だけを使用します。このメモリ・ブロックがなくなると、まだ生きているオブジェクトがもう一方のブロックにコピーされ、使用済みのメモリ空間が1つずつ片付けられていきます。これは、各時間は、メモリの回復の全体の半分になり、メモリの割り当てがメモリの断片化やその他の複雑さを考慮する必要はありません、限り、ヒープポインタの先頭としてメモリを確保するために移動することができます、実装が簡単で、効率的に実行されますが、このアルゴリズムのコストは、価格の元の半分にメモリを削減することです少し高すぎる

レプリケーション・アルゴリズムの実行を以下に示します:

現在、商用仮想マシンはこの収集アルゴリズムを使って新世代の再生を行っています。IBMの特別な調査によると、新世代のオブジェクトの98%は生まれて死ぬのでメモリ空間を1対1の比率に従って分割する必要はありません。 その代わりに、メモリをより大きなEden空間と2つの小さなSurvivor空間に分割し、毎回、EdenとSurvivor空間の一方を使用します。再生成されると、EdenSurvivor生存しているオブジェクトはもう一方の Survivor スペースに一度にコピーれ、再生成処理の最後に、使用されたばかりのEdenSurvivor スペースがクリーンアップされます。使用可能なメモリ領域はフレッシュ世代全体の容量の90%で消費されるメモリは10%だけです。もちろん、オブジェクトの98%が回復することができますちょうど一般的なシナリオのデータであり、各回復が唯一のオブジェクトの10%以上の生存であることを保証する方法はありません、Suvivorスペースが十分でない場合は、割り当て保証のために他のメモリに依存する必要があります。

メモリの割り当て保証は、銀行にお金を借りに行くようなものです、評判が非常に良い場合は、ケースの98%では、時間通りに返済することができますので、銀行は、次の時間にも時間通りに返済することができ、ローンの金額で、ちょうど保証人を持つ必要があります私はお金を返すことができない場合は、彼の口座から引き落とすことができることを保証することができますし、銀行はリスクがないと思います。同じことがメモリの割り当て保証に適用され、別の生存者空間が最後の新しい世代から収集された生存オブジェクトを格納するのに十分なスペースを持っていない場合、これらのオブジェクトは、割り当て保証メカニズムを通じて古い世代に直接行くでしょう

マーキング組織化アルゴリズム

コピー収集アルゴリズムはオブジェクトの生存率が高いときに多くのコピー操作を実行しなければならない場合、効率が悪くなります。さらに致命的なのは、50%の領域を無駄にしたくないのであれば、使用中のメモリ内のすべてのオブジェクトが100%生存しているという極端なケースに備えて保証を割り当てる領域を余分に確保する必要があるため、昔はこのアルゴリズムが直接選択されることはありませんでした

古い時代の特徴に基づき、別のマーククリーンアルゴリズムが提案されています。マークプロセスはマーククリーンアルゴリズムと同じですが、回復可能なオブジェクトを直接クリーンアップする代わりに、後続のステップでは、すべての生存オブジェクトを一方の端に移動さ、その後、端の境界の外側のメモリを直接クリーンアップします

ラベリング-フィニッシング・アルゴリズムの実行を下図に示します:

世代収穫アルゴリズム

現在の商用仮想マシンのゴミ収集では世代別収集アルゴリズムを使用しています。これは新しいアイデアではありませんが、オブジェクトの生存サイクルの違いに応じてメモリをいくつかのブロックに分割するだけです。一般に、Javaのヒープは新世代と旧世代に分けられ、各世代の特性に応じて最適な収集アルゴリズムを使用できるようになっています。新しい世代では、毎回ゴミのコレクションは、オブジェクトの死者の数が多い生存者のわずかな数を発見し、アルゴリズムをコピーすることを選択し、唯一のコレクションのコストを完了することができますコピーする生存オブジェクトの数を支払う必要があります。古い世代ではオブジェクトの高い生存率とそれに保証を割り当てるための余分なスペースの不足のため、それはリサイクルのためのマーククリーンアルゴリズムまたはマークソートアルゴリズムを使用する必要があります。

HotSpotのアルゴリズム実装

先にオブジェクト生存判定アルゴリズムとゴミ収集アルゴリズムを紹介しましたが、これらのアルゴリズムをHotSpot VMに実装する場合、VMが効率的に動作するようにアルゴリズムの実行効率を厳密に考慮する必要があります。

ルートノードの列挙

この操作の参照チェーンを見つけるためにGCのRootsノードからの到達性の分析から、たとえば、GCのRootsノードとして使用することができます主にグローバルな参照と実行コンテキストでは、今、多くのアプリケーションだけでメソッド領域はメガバイトの数百を持っている、あなたが1つずつ、この中の参照をチェックしたい場合は、必然的に多くの時間を消費します。

さらに、一貫性を保証するスナップショットで解析を実行する必要があるため、到達可能性解析はGCストールの観点から実行時間に敏感です。一貫性とは、解析全体を通して実行システム全体がある時点でフリーズしているように見え、解析の進行中にオブジェクトの参照や関係が変更されないことを意味します。この点が満たされないと、分析結果の正確性が保証されません。これがGCが実行されるときにJavaの実行スレッドがすべて停止されなければならない主な理由の1つであり、停止されないと言われているCMSコレクタにおいてもルートノードの列挙は停止されなければなりません

現在主流のJava仮想マシンは正確なGCを使用しているため、実行システムが停止したときに、すべての実行コンテキストとグローバル参照の場所を1つも見逃さずにチェックする必要はなく、仮想マシンはオブジェクト参照がどこに格納されているかを直接知る方法を持つ必要があります。HotSpotの実装では、この目的のためにOopMapと呼ばれるデータ構造のセットを使用しています。クラスのロードが完了すると、HotSpotはオブジェクト内のどのオフセットにどのタイプのデータがあるかを計算し、JITコンパイル中にスタック上やレジスタ内のどの場所が特定の場所の参照であるかも記録します。こうすることで、GCはスキャン時にこの情報を直接知ることができます。

セキュリティポイント

OopMapの助けを借りて、HotSpotは素早く正確にGC Rootsの列挙を完了することができますが、非常に現実的な問題が発生します:参照関係の変更やOopMapの内容の変更につながる可能性のある命令がたくさんあり、これらの命令ごとに対応するOopMapを生成すると多くの余分なスペースが必要になり、GCのためのスペースのコストが非常に高くなります。が非常に高くなります。

実際、HotSpotはすでに述べたようにすべての命令に対してOopMapを生成するわけではなくセーフポイントと呼ばれる指定された場所でのみこの情報を記録します。つまり、プログラムの実行はあらゆる場所でGCを停止したり開始したりするのではなく、セーフポイントに到達したときだけ一時停止します。セーフポイントは、GCの待ち時間が長くなりすぎるほど少なくても、実行時の負荷が増えすぎるほど頻繁に選択されるべきではありません。セーフポイントは、GCの待ち時間が長くなりすぎるほど少ないものでも、実行時の負荷が増えすぎるほど頻繁なものでもないはずです。したがって、セーフポイントの選択は、基本的にプログラムが長時間実行できる特徴を持っているかどうかという基準に基づいています。各命令の実行時間は非常に短いので命令ストリームの長さのためにプログラムが長時間実行される可能性は低く、長時間実行の最も明白な特徴は、命令シーケンスの多重化、例えば、メソッド呼び出し、ループジャンプなどです。長時間実行の最も明白な特徴は、メソッド呼び出しループジャンプ例外ジャンプなどの命令シーケンスの多重化であるため、Safepointを生成するのはこれらの特徴を持つ命令です。

SafepointではGCが発生したときに停止する前に、すべてのスレッドを最も近いセーフポイントで実行させる方法も考慮すべき課題です。プリエンプティブ割り込みとアクティブ割り込みの2つのオプションがあり、プリエンプティブ割り込みはスレッドの実行コードが積極的に協力する必要はありません。GCが発生すると、まずすべてのスレッドに割り込みをかけ、スレッドが安全なポイント以外のどこかで割り込まれていることがわかったら、スレッドを再開して安全なポイントで実行させます。今日、GCイベントに応答してスレッドを中断するためにプリエンプティブ割り込みを使用するVM実装はほとんどありません

アクティブ割り込みの考え方は、GCがスレッドに割り込みをかける必要があるときにスレッドに直接操作するのではなく、単にフラグを設定し、各スレッドが実行時にアクティブにフラグをポーリングし、割り込みフラグが真であることを発見したときに割り込みをかけて自分自身をハングアップさせるというものです。マーカーのポーリングと安全ポイントは重複しており、さらにメモリを確保するためにオブジェクトを作成する必要があります

安全エリア

Safepontを使うことで、GCへのアクセス方法の問題は完璧に解決されたように見えますが、現実は必ずしもそうではありません。Safepointのメカニズムは、プログラムが実行されているとき、それほど長くない期間内にGCにアクセス可能なSafepointに遭遇することを保証します。いわゆるプログラムが実行されていないCPU時間が割り当てられていない、典型的な例は、スレッドがハングを中断する安全な場所に行くためにJVMの割り込み要求に応答することができないスリープ状態またはブロック状態のスレッドであり、JVMはまた、明らかにスレッドがCPU時間を再割り当てされるのを待つことはほとんどありません。この状況のために、それは解決するために**安全な領域**に必要です。

セーフ領域は、参照関係が変化しないコード断片ですセーフ領域はセーフポイントを拡張したものと考えることもできます。

スレッドが安全領域でコードを実行するとき、スレッドはまず自分自身が安全領域に入ったことを識別します。そのため、この間にJVMがGCを開始するとき、安全領域状態にあることを識別するスレッドを気にする必要はありません。スレッドがセーフ・リージョンを離れたいときは、システムがルート・ノードの列挙を完了したかどうかをチェックする必要があります

ゴミ収集人

収集アルゴリズムがメモリ再利用の方法論であるならば、ごみコレクタはメモリ再利用の具体的な実装です。Java仮想マシンの仕様にはごみコレクタの実装方法についての規定がないため、ベンダーや仮想マシンのバージョンによって提供されるごみコレクタは大きく異なり、一般的には、ユーザが自分のアプリケーションの特性や要求に応じてごみコレクタを組み合わせるためのパラメータを提供します。アプリケーションの特性や要件に応じて、各時代で使用されているコレクター。ここで説明するコレクターはJDK 1.7 Update 14以降のHotSpot 仮想マシンに基づいており、7 種類のコレクターがあります:シリアルコレクターParNew コレクターParellel Scavenge コレクターParallel Scavenge コレクターSerial Old コレクターParallel Old コレクターCMS コレクターG1 コレクターです:

上の図は、異なるサブ世代に作用する7 つのコレクタを示しており、2 つのコレクタの間に接 続がある場合は、一緒に使用できることを意味します。仮想マシンが置かれている領域は、新世代のコレクタに属するか、旧世代のコレクタに属するかを示します。

そのため、特定のアプリケーションに最適なものを選択することになります。すべてのシナリオで機能する完璧なコレクターが存在すれば、HotSpot VMがこれほど多くの異なるコレクターを実装する必要はありません。

メモリ割り当てとリサイクル戦略

Java技術体系で提唱されている自動メモリ管理は、結局のところ、オブジェクトへのメモリ割り当てとオブジェクトに割り当てられたメモリの再利用という2つの問題の自動解決に集約されます。

オブジェクトのメモリ確保は、一般的な方向性としてはヒープ上に行われ、オブジェクトは主に新しい世代のEden領域に確保され、ローカルのスレッド確保バッファが有効になっている場合は、スレッドはまずTLABに確保されます。割り当てのルールは100%固定されているわけではなく詳細は現在どのゴミコレクタの組み合わせが使用されているかまた仮想マシンのメモリ関連パラメータの設定に依存します

最も一般的なメモリ割り当てルールはいくつかあります:

  • オブジェクトは Eden で最初に割り当てられます。
  • 老年期に直接大きな物
  • 長く生き続けるものは、老いを迎えます。
  • 動的な物体年齢決定
  • スペース割り当て保証
Read next

抽象ファクトリー・パターンを1つの記事で理解する

抽象ファクトリーパターンは、具体的なクラスを指定することなく、関連または相互依存する一連のオブジェクトを作成するためのインターフェイスを提供します。抽象ファクトリーは、その概念だけでも非常に抽象的です。抽象ファクトリーパターンを理解する前に、まず抽象ファクトリーが導入した2つの概念を理解してください:製品ファミリーと製品階層 簡単に言うと、次の図のようになります。

May 16, 2020 · 4 min read