メモリ管理はコンピュータ ソフトウェア開発の重要なコンポーネントであり、アプリケーションでのメモリの効果的な割り当て、利用、解放を担当します。その重要性は、ソフトウェアのパフォーマンスを向上させ、システムの安定性を確保することにあります。
ガベージ コレクション (GC) は、Java や Go などの現代のプログラミング言語において極めて重要です。未使用のメモリを自律的に検出してリサイクルするため、開発者が手動でメモリを管理する必要性が軽減されます。 GC の概念はもともと 1950 年代後半に LISP プログラミング言語で登場し、自動メモリ管理の導入を示しました。
自動メモリ管理の主な利点は次のとおりです。
メモリ内の「ゴミ」の性質を理解し、再利用可能な領域を特定することが不可欠です。次の章では、ガベージ コレクションの基本原理を探ることから始めます。
参照カウント アルゴリズムは、オブジェクトのヘッダーにフィールドを割り当てて、その参照カウントを追跡します。この数は、新しい参照ごとに増加し、参照が削除されると減少します。カウントが 0 に達すると、オブジェクトはガベージ コレクションの対象になります。
次のコードを考えてみましょう:
まず、d によって参照される値のデモを含む文字列を作成します (図 1)。
String d = new String("demo");
図 1 – 文字列の作成後
次に、d を null に設定します。デモの参照カウントはゼロです。参照カウント アルゴリズムでは、デモ用のメモリが再利用されます (図 2)。
d =null; // Reference count of 'demo' becomes zero, prompting garbage collection.
図 2 – 参照が無効化された場合
参照カウント アルゴリズムはプログラムの実行中に動作し、ガベージ コレクションのためにプログラムを一時的に停止する Stop-The-World イベントを回避します。ただし、その大きな欠点は、循環参照を処理できないことです (図 3)。
例:
public class CircularReferenceDemo { public CircularReferenceDemo reference; private String name; public CircularReferenceDemo(String name) { this.name = name; } public void setReference(CircularReferenceDemo ref) { this.reference = ref; } public static void main(String[] args) { CircularReferenceDemo objA = new CircularReferenceDemo("Ref_A"); CircularReferenceDemo objB = new CircularReferenceDemo("Ref_B"); objA.setReference(objB); objB.setReference(objA); objA = null; objB = null; } }
ここでは、外部参照を無効化しているにもかかわらず、objA と objB 間の相互参照によりガベージ コレクションが妨げられています。
図 3 – 循環参照
両方のオブジェクトにアクセスできなくなっていることがわかります。ただし、これらは相互に参照されるため、参照カウントがゼロになることはありません。したがって、GC コレクターは、参照カウント アルゴリズムを使用してそれらをガベージ コレクションするように通知されることはありません。
このアルゴリズムは、std::shared_ptr を使用して C++ で実際に実装されます。動的に割り当てられたオブジェクトのライフサイクルを管理するように設計された std::shared_ptr は、オブジェクトへのポインターが作成または破棄されるときの参照カウントの増加と減少を自動化します。このスマート ポインタは C++ 標準ライブラリの一部であり、手動メモリ処理に伴うリスクを大幅に軽減する堅牢なメモリ管理機能を提供します。 std::shared_ptr がコピーされるたびに、新しい参照を反映して、管理オブジェクトの内部参照カウントが増加します。逆に、std::shared_ptr が破棄されるか、スコープ外になるか、別のオブジェクトに再割り当てされると、参照カウントは減少します。割り当てられたメモリは自動的に再利用され、参照カウントが 0 に達するとオブジェクトは破棄されます。
オブジェクトが不必要に割り当てられたままにならないようにすることで、メモリ リークを効果的に防止します。
到達可能性分析アルゴリズムは GC ルートから始まり、オブジェクト グラフを通過します。これらのルートから到達できないオブジェクトは回復不可能とみなされ、収集の対象となります。
下の画像に示すように、青色の円で囲まれたオブジェクトは存続し、灰色の円で囲まれたオブジェクトはリサイクルできます (図 4)。
図 4 – メモリ リーク
この方法は、参照カウント アルゴリズムに固有の循環参照の問題を効果的に解決します。 GC ルートから到達できないオブジェクトは、収集のために分類されます。
通常、GC ルートと見なされる Java オブジェクトには次のものがあります。
GraalVM は、Java アプリケーションを GraalVM ネイティブ イメージと呼ばれるスタンドアロンの実行可能バイナリに変換する、Ahead-of-Time (AOT) コンパイラを提供します。 Oracle Labs によって開発されたこれらのバイナリ
アプリケーションおよびライブラリ クラス、GC などのランタイム コンポーネントをカプセル化し、Java ランタイム環境 (JRE) なしで操作できるようにします。
このプロセスには、到達可能なコンポーネントを決定する静的解析、実行されたブロックによる初期化、後続のマシンコード変換のためのアプリケーション状態のスナップショットの作成による最終処理が含まれます。
Substrate VM は、Oracle Labs によって調整された GraalVM スイートの不可欠な部分として機能します。これは、事前 (AOT) コンパイルをサポートするだけでなく、JavaScript、Python、Ruby、さらには C や C++ などのネイティブ言語など、Java 以外の言語の実行も容易にする強化された JVM です。その中核となる Substrate VM は、GraalVM が Java アプリケーションをスタンドアロンのネイティブ バイナリにコンパイルできるようにする高度なフレームワークとして機能します。これらのバイナリは、実行時に従来の Java 仮想マシン (JVM) に依存しないため、デプロイメントと
が合理化されます。
運用プロセス。
Substrate VM の主要な機能の 1 つは、その特殊なガベージ コレクターであり、低レイテンシと最小限のメモリ フットプリントを必要とするアプリケーション向けに微調整されています。このガベージ コレクターは、標準の JVM 上で実行される従来の Java アプリケーションとは大きく異なる、ネイティブ イメージに特有の固有のメモリ レイアウトと運用モデルの処理に熟達しています。 Substrate VM ネイティブ イメージに Just-In-Time (JIT) コンパイラーが存在しないのは、実行可能ファイル全体のサイズを最小限に抑えるのに役立つ戦略的な選択です。これは、サイズと複雑さが大幅に異なる JIT コンパイラーと関連メタデータを含める必要がなくなるためです。
さらに、GraalVM は Java を使用して開発されていますが、これにより、特にネイティブ メモリ アクセスに関して特定の制約が生じます。このような制限は、主にセキュリティ上の懸念と、さまざまなプラットフォーム間で互換性を維持する必要性によるものです。ただし、最適なガベージ コレクション操作には、ネイティブ メモリへのアクセスが不可欠です。これに対処するために、Substrate VM は、ネイティブ メモリとの安全かつ効率的な対話を促進する一連の特殊なインターフェイスを採用しています。これらのインターフェイスは、より広範な GraalVM アーキテクチャの一部であり、Java の安全性と管理性を維持しながら、Substrate VM が C などの低レベル言語に似た方法でメモリを効果的に管理できるようにします。
実際には、これらの機能により、Substrate VM は、GraalVM でコンパイルされたアプリケーションの機能と効率を強化する非常に多用途なツールになります。開発者に
を許可することで、
Substrate VM は、より幅広いプログラミング言語を活用し、それらを効率的なネイティブ バイナリにコンパイルすることで、従来の Java 開発環境で達成できる限界を押し広げます。これにより、高いパフォーマンス、リソース消費の削減、多用途の言語サポートが求められる最新のソフトウェア開発プロジェクトにとって、非常に貴重な資産となります。
サブストレート VM の注目すべき要素は次のとおりです。
生のメモリ操作用の Pointer Interface Pointer や、ワード サイズの値を処理するための WordBase Interface WordBase などのインターフェイスを介したメモリ アクセスが簡素化されました。
動的オブジェクト割り当てのため、ヒープを不変オブジェクトを含む事前に初期化されたセグメントとランタイム セグメントに分割します (図 5)。
図 5 – ネイティブ イメージのメモリ管理
実行時、サブストレート VM のいわゆるイメージ ヒープには、イメージのビルド プロセス中に作成されたオブジェクトが含まれます。ヒープのこのセクションは、実行可能バイナリのデータ セクションのデータで事前に初期化されており、アプリケーションの起動時にすぐにアクセスできます。イメージ ヒープに存在するオブジェクトは不滅とみなされます。したがって、これらのオブジェクト内の参照は、
によってルート ポインタとして扱われます。
ガベージコレクター。ただし、GC はルート ポインターのイメージ ヒープの一部、特に読み取り専用としてマークされていない部分のみをスキャンします。
ビルド プロセス中、読み取り専用として指定されたオブジェクトは、イメージ ヒープの特定の読み取り専用セクションに配置されます。これらのオブジェクトは実行時に割り当てられたオブジェクトへの参照を保持しないため、ルート ポインターが含まれず、スキャン中に GC がそれらをバイパスできます。同様に、プリミティブ データまたはプリミティブ型の配列のみで構成されるオブジェクトにもルート ポインターがありません。この属性は、これらのオブジェクトを GC スキャンから省略できるため、ガベージ コレクション プロセスをさらに合理化します。
対照的に、Java ヒープは、実行時に動的に作成される通常のオブジェクトを保持するように設計されています。ヒープのこの部分は、使用されなくなったオブジェクトによって占められていた領域を再利用するために、定期的にガベージ コレクションの対象となります。これは、エージングのメカニズムを備えた世代ヒープとして構造化されており、長期にわたる効率的なメモリ管理を容易にします。
事前に初期化された不滅のイメージ ヒープと動的に管理される Java ヒープを分割することで、Substrate VM はメモリ使用量とガベージ コレクションの効率を最適化し、アプリケーションのメモリ要件の静的側面と動的側面の両方に対応できます。
Substrate VM のヒープ モデルでは、メモリはヒープ チャンクと呼ばれる構造に体系的に編成されます。これらのチャンクは通常、デフォルトで 1024KB のサイズで、オブジェクト ストレージのみに割り当てられる仮想メモリの連続セグメントを形成します。これらのチャンクの組織構造はリンクされたリストであり、末尾のチャンクが最後に追加されたセグメントを表します。こんなモデル
効率的なメモリ割り当てとオブジェクト管理が容易になります。
これらのヒープ チャンクは、アライメントとアンアライメントの 2 つのタイプにさらに分類されます。整列されたヒープ チャンクは、複数のオブジェクトを連続的に保持できます。この配置により、
のマッピングがより簡単になります。
オブジェクトをそれぞれの親ヒープ チャンクに追加することで、メモリ管理がより直観的かつ効率的になります。オブジェクトのプロモーションが必要なシナリオ (通常はガベージ コレクションと
)
メモリの最適化 - オブジェクトは、親ヒープ チャンク内の元の配置から、指定された「古いコピー先スペース」にあるターゲット ヒープ チャンクに移動されます。この移行は世代別ヒープ管理戦略の一部であり、古いオブジェクトから若いオブジェクトを分離することでガベージ コレクション プロセスの最適化に役立ち、それによって GC サイクル中のオーバーヘッドを削減します。
GraalVM ネイティブ イメージは、さまざまなニーズに合わせて調整されたさまざまな GC をサポートします。
シリアル GC: シングルスレッド アプリケーションに適したデフォルトの低フットプリント コレクター。
G1 ガベージ コレクター: ヒープ サイズが大きいマルチスレッド アプリケーション向けに設計されており、世代管理の柔軟性が強化されています。
Epsilon GC: 割り当ては処理しますが、再利用は行わない最小限のコレクターで、ヒープの完全な使用率が予測可能な短期間のアプリケーションに最適です。
結論として、Substrate VM は、特殊なガベージ コレクションや構造化ヒープ管理などの高度な技術を組み込むことで、GraalVM 内のメモリ管理を効果的に最適化します。ヒープ チャンクや、イメージ ヒープと Java ヒープ用の個別のメモリ セグメントなどのこれらの機能により、ガベージ コレクションが合理化され、アプリケーションのパフォーマンスが向上します。 Substrate VM はさまざまなプログラミング言語をサポートし、それらを効率的なネイティブ バイナリにコンパイルするため、最新の JVM フレームワークが従来の境界を超えて拡張し、多様なアプリケーション環境での実行効率と堅牢性を強化する方法を示します。このアプローチは、仮想マシン テクノロジとアプリケーションの展開における将来の開発に高い基準を設定します。
以上がGraalVM ネイティブ イメージのメモリ管理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。