Javaのガベージコレクションは、プログラムで使用されなくなったオブジェクトを削除することで、メモリを自動的に回収します。このプロセスは、メモリリークの防止、パフォーマンスの向上、そして開発者が手動でメモリを管理する手間の軽減に役立ちます。
ガベージコレクションは、コーディングの世界ではお馴染みの用語です。Javaプログラミング言語を学ぶ際にも、必ず目にするでしょう。Javaのメモリ管理機能に組み込まれているため、ガベージコレクターはJavaの重要な機能の一つです。ガベージコレクターは深刻なエラーを防ぎ、プログラマーが不要なオブジェクトを気にすることなく新しいオブジェクトを作成できるようにします。
しかし、ガベージコレクション(GC)を実行するバックグラウンドスレッドは予測不可能なタイミングで実行されるため、アプリケーションのパフォーマンスを低下させたり、速度を低下させたり、不要な遅延を引き起こしたりする可能性があります。このようなパフォーマンスへの影響から、開発者はプログラム実行時に遅延が発生しないように、適切なガベージコレクターを明確に理解する必要があります。
この記事では、Javaでのガベージコレクションに伴う詳細について説明します。 また、ガベージコレクションの主な利点と、ガベージコレクションがどのように機能するかについての簡単な説明が含まれており、開発者と管理者がアプリケーションでガベージコレクションをより簡単に使用できるようになります。
TL; DR




コンテンツ
- ガベージコレクションとは何ですか?
- ガベージコレクションの利点は何ですか?
- ガベージコレクションはJavaでどのように機能しますか?
- 世代別ガベージコレクション
- ごみ収集活動
- 参照されていないオブジェクト
- オブジェクトを参照しないようにするにはどうすればよいですか?
- ガベージコレクションのルーツ
- Java仮想マシンのガベージコレクターのタイプ
- Javaメモリ管理
- JVMメモリ構造とは何ですか?
- まとめ:
ガベージコレクションとは何ですか?
ガベージコレクションとは、未使用のランタイムメモリを再利用する自動プロセスです。つまり、未使用のオブジェクトは自動的に破棄されるため、メモリの割り当てと解放を気にすることなく新しいオブジェクトを作成できます。
CやC++などの言語では、プログラマーがオブジェクトを手動で作成・破棄するため、冗長なオブジェクトの管理と継続的な破棄は困難になる可能性があります。システムが不要なオブジェクトを過剰に保存すると、メモリが最新のオブジェクトを効率的に割り当てることができなくなる可能性があります。
さらに、手動で割り当てると、特にプログラマが不要なメモリを解放しなかった場合や、メモリ ヒープ内のオブジェクトが実行中のコードからアクセスできなくなった場合に、システムがメモリ リークの影響を受けやすくなります。
Javaプログラムはで実行されます Java仮想マシン (JVM)バイトコードの形式。 JVMは、バイトコードを解釈してプログラムを実行し、ヒープスペースまたはプログラムに割り当てられたメモリ部分にオブジェクトを作成できるようにします。
新しいオブジェクトの作成と解放は、一部のオブジェクトが完全に不要になるまで続きます。 その時点で、ヒープにはXNUMXつのタイプのオブジェクトが含まれています。これらは次のように記述できます。
デッド:不要なオブジェクトまたは使用されなくなったオブジェクト。
ライブ: 使用中および参照中のオブジェクト。
Java のガベージ コレクションはメモリを自動的に管理するため、開発者は効率的で高性能なアプリケーションの構築に集中できます。
Javaにおけるガベージコレクションの利点
多くのプログラマーは、明示的なストレージ再利用のパフォーマンスは、メモリ管理における自動ガベージコレクションよりも優れていると考えています。 ただし、いくつか 研究 ガベージコレクターの下で十分に開発されたシステムは、明示的な割り当て解除を使用したシステムよりも優れた結果を生み出すことを示しました。 ガベージコレクションの利点のいくつかを次に示します。
- 自動割り当て解除は、開発者が手動でメモリを解放し、システムの書き込み性を高め、開発の時間とコストを節約するのに役立ちます。
- 管理対象ヒープにオブジェクトを割り当てるのは効率的です。
- オブジェクトがメモリ割り当てを使い果たしたときに、別のオブジェクトに割り当てられたメモリを使用できないように、メモリの安全性を提供します。
- 使用されなくなったオブジェクトを再利用してメモリをクリアすることにより、ガベージコレクションはメモリを解放し、将来使用できるようにします。 最初はクリーンなコンテンツがあるため、開発者はすべてのフィールドを開始する必要はありません。
- ガベージコレクションにより、プログラムの効率が保証されます。
ガベージコレクションはJavaでどのように機能しますか?
Javaにおけるガベージコレクションは、ヒープメモリ内の有用なオブジェクトとそうでないオブジェクトを識別し、使用されていないオブジェクトを削除する自動処理です。プログラムの実行コードからアクセスできないオブジェクトによって占有されているメモリは、解放されて使用可能になります。
他の言語とは異なり、JavaではJVMが不要なデータを管理するため、プログラマーはオブジェクトによって実行されるすべてのアクティビティを制御する必要はありません。JVMはガベージコレクターに指示を出し、ヒープが大きくなると自動的にクリーンアップします。
次に、XNUMXつの基本的な手順でガベージコレクションがどのように行われるかを確認します。
- マーク: この段階では、ガベージコレクターがオブジェクトが使用済みか未使用かを識別します。アプリケーションによって参照されなくなった未使用オブジェクトは削除対象としてマークされ、アプリケーションによってまだ参照されているオブジェクトは使用可能なものとして保持されます。
- 掃く: この段階では、参照されていないオブジェクトをクリアしてスペースを解放します。ガベージコレクターは、ライブオブジェクトとそれに関連付けられたポインタを保持しながら、参照されていないオブジェクトによって占有されていたヒープメモリを解放し、新しいオブジェクトのためのスペースを確保します。
- コンパクト: これは、フラグメント化されたオブジェクトをヒープの先頭から再配置して、新しく割り当てられたオブジェクト用のスペースを作成する最後のステップです。 再配置のための空きスペースは、ガベージコレクターによってクリアされた不要なメモリに起因し、プログラムの実行時に効率的なパフォーマンスをもたらします。
最も基本的なガベージコレクションレベルは、マーク、スイープ、コンパクトアルゴリズムです。ただし、ほとんどのオブジェクトの寿命が短いため、マーク、スイープ、コンパクトのプロセスを完全に実行できない場合があります。
その結果、プログラマーは、すべての短期間のオブジェクトを確実に管理するために、より効率的なGCアルゴリズムを必要としています。
世代別ガベージコレクション
世代別ガベージコレクションアルゴリズムは、ガベージをより効率的に収集するために、オブジェクトの寿命の観点からオブジェクトを配置します。 ガベージコレクターは、その存在期間に応じて異なるレベルを作成することにより、すべての短命のオブジェクトで完全に動作することを保証します。 さらに、ヒープメモリを若い世代と古い世代のXNUMXつの主要なコンパートメントに分割します。
若い世代
若い世代はすべての新しいオブジェクトを運びます。 これは、EdenとSurvivorのXNUMXつのパーティションに分割されています。
エデン:すべての新しいオブジェクトは、ガベージコレクションサイクルごとに、サバイバーパーティションに移動する前にここに配置されます。
サバイバー:サバイバーはSOとS1に分けられ、FromSpaceとToSpaceとも呼ばれます。
オブジェクト割り当てのフローは次のようになります。
- まず、すべての新しいオブジェクトがEdenパーティションに割り当てられ、両方のSurvivorパーティションは空のままになります。
- 時間の経過とともに、Edenパーティションがいっぱいになり、新しい割り当てを実行できなくなります。 これにより、JVMはマイナーなガベージコレクションを実行し、参照されるオブジェクトにマークを付け、それをS0パーティションに転送して、S1にスペースを作成します。
- エデンが再び完全になったときにも、同様のプロセスが発生します。 まず、JVMはマイナーなガベージコレクションプロセスを実行します。 次に、EdenおよびS0部門で使用されているオブジェクトを識別し、それらをS1に移動します。 これは、S1またはS0のいずれかが常に空になることを意味します。
- 次のマイナーガベージコレクションは、サバイバースペースが切り替わる点を除いて、上記で説明したものと同様です。 オブジェクトは、S1からS0ではなく、S0からS1に移動されます。 ライブオブジェクトはS0に残ります。
旧世代に昇格する前に、ガベージコレクションはXNUMX番目とXNUMX番目のステップで時間がかかります。 オブジェクトが長寿命であると識別された後、ガベージコレクタはそれらを古いオブジェクトに移動します。
旧世代
若い世代とは異なり、このコンパートメントは、主要なGC操作のマーキング、スイープ、および実行に重点を置いています。完全なガベージコレクションサイクルでは、すべてのライブオブジェクトを若い世代から古い世代に昇格させ、利用可能なスペースを圧縮することで、両方の世代をクリーンアップします。
古い世代は、既存のすべてのオブジェクトを保護し、完全なガベージコレクションが開始されたときにアプリケーションを一時停止することで、新しいオブジェクトがヒープメモリに移動されないようにします。
ごみ収集活動
ガベージコレクションには、次のXNUMX種類のアクティビティが含まれます。
マイナーまたはインクリメンタルガベージコレクション
この操作は若い世代で実行され、ヒープメモリで見つかった到達不能なオブジェクトをクリアします。
メジャーまたはフルガベージコレクション
メジャーガベージコレクションは、マイナーガベージコレクションでクリアされずに古いヒープメモリにコピーされたオブジェクトを識別して削除します。残ったオブジェクトは圧縮され、新しい割り当てのためのスペースが確保されます。このプロセスは若い世代よりも頻度が低いため、古い世代ではガベージコレクションの頻度が低くなります。
参照されていないオブジェクト
参照されていないオブジェクトは、プログラマーにとって価値がなくなったオブジェクトを示します。 この場合、すべてのオブジェクトから基準点を引いたものは不要と見なされます。 ヒープメモリにスペースを作成するために、ガベージコレクタはこれらの参照されていないオブジェクトを破棄し、メモリを再利用して圧縮し、新しい割り当てのためにスペースを準備します。
Javaにおけるガベージコレクションの課題
Javaのガベージコレクションは強力なメモリ管理ツールですが、癖がないわけではありません。開発者が直面する最も一般的な課題を以下に示します。
1. STW(ストップ・ザ・ワールド)一時停止
最も顕著な問題の一つは、「ストップ・ザ・ワールド」イベントです。JVMがガベージコレクションサイクルを実行する際、すべてのアプリケーションスレッドが一時停止してジョブを実行することがあります。この一時停止は、ヒープサイズと使用されているGCアルゴリズムに応じて、数ミリ秒から数秒続く可能性があり、レイテンシの影響を受けやすいアプリケーション(取引プラットフォームやリアルタイムゲームなど)のユーザーエクスペリエンスに深刻な影響を与えます。
2. Javaのメモリリーク
自動GCを使用しても、メモリリークが発生する場合があります。これは通常、オブジェクトが意図せずメモリ内に保持され(例えば、静的フィールドや適切に管理されていないキャッシュなど)、ガベージコレクションの対象から外れてしまう場合に発生します。
3. ヒープの断片化
ヒープの断片化は、空きメモリが小さな塊に分散しているときに発生し、空き領域全体が十分であるように見えても、大きなオブジェクトを割り当てることが困難になります。これは、旧世代の空間ではより深刻な問題となります。
4. 過剰なオブジェクト生成と短いオブジェクト寿命
短命オブジェクトを頻繁に作成および破棄するアプリケーション (たとえば、タイトなループや高スループットのサービス内) は、若い世代に負荷をかけ、頻繁にマイナー GC をトリガーして CPU 使用率を増加させる可能性があります。
5. 本番環境での予測不可能なGC動作
GCの動作は、ワークロード、メモリの可用性、JVMフラグの違いにより、開発環境と本番環境で大きく異なる場合があります。そのため、本番環境でのデバッグとチューニングは容易ではありません。
オブジェクトを参照しないようにするにはどうすればよいですか?
プログラマは不要なオブジェクトを破棄する責任はありませんが、不要になったオブジェクトはアクセス不能にする必要があります。参照されていないオブジェクトが削除されない場合、ヒープメモリがいっぱいになり、プログラムのパフォーマンスが低下します。これは通常、メモリリークと呼ばれます。簡単なトリックによって、オブジェクトへの参照が省略され、ガベージコレクションの対象になることがあります。具体的には、次のようなものがあります。
- 参照変数の再割り当て。
- 参照をnullにします。
- 匿名オブジェクトを使用します。
ガベージコレクションのルーツ
ガベージコレクションのルートは、ガベージコレクションプロセスにおける一意のオブジェクトです。 これらは主にガベージコレクションの開始点であり、JVMによって参照されます。 したがって、直接または間接的に参照される他のすべてのオブジェクトがガベージコレクションされないようにします。 すべてのアプリケーションまたはプログラムは、ツリーの他の部分に到達するためにルートにアクセスできる必要があります。 以下は、JavaのXNUMXつの主要なガベージコレクションルートです。
- ローカル変数: スレッドのスタックがそれらを接続している限り、これらは存続します。
- アクティブなJavaスレッド: アクティブなJavaスレッドは、ライブスレッドと見なされるため、ガベージコレクションのルートリストに加わります。
- 静的変数: 静的変数はクラスに参照されます。 したがって、これらのガベージコレクターのルートは、クラスがロードされるときにクリアランスの対象にはなりません。 クラスはガベージコレクションされ、参照されているすべての静的変数を削除できます。 これは、一般にクラスローダーまたはアプリケーションサーバーを使用する場合に不可欠です。
- JNIリファレンス: これらのJavaオブジェクトは、ガベージコレクタがネイティブコードとして参照されている到達不能なオブジェクトを見つけるのに役立ちます。JNI参照はこれらの種類のオブジェクトを公開し、JVMがそれらを処理できるようにします。ネイティブコードとして参照されているオブジェクトが識別されない場合、JVMはそれらのオブジェクトに対してガベージコレクションを実行できない可能性があります。
Java仮想マシンのガベージコレクターのタイプ
ガベージコレクションは、参照されていないオブジェクトをヒープから削除し、新しく設計されたオブジェクトに十分なスペースを提供することにより、Javaメモリで重要な役割を果たします。 JVMは異なります ガベージコレクターの種類。 それぞれの包括的な詳細は次のとおりです。
シリアルGC
シリアルガベージコレクタは、シングルスレッドプロセスで実行されるアプリケーション向けに特別に開発されました。シリアルGCは、マルチスレッドアプリケーションが単一のスレッドでシリアルGCを実行する際に、すべてのマルチスレッドアプリケーションをブロックし、ガベージコレクションを連続的に実行できるようにします。ガベージコレクションサイクルの終了後、シリアルガベージコレクタはメモリを圧縮し、断片化を回避します。
一時停止時間が短いアプリケーションは、ガベージコレクションに干渉する可能性があるため、お勧めしません。 この干渉は通常、シリアルGCが一時停止アプリケーションを開始している間にアプリケーションが通常のアクティビティを再開したときに発生します。これは一般に「ワールドイベントの停止」として知られています。
パラレルGC
並列GCは、ヒープメモリシステムをマルチスレッドプロセッサで実行することで、大規模データに対して効率的に機能します。これは通常、JVMのアクティビティにおけるデフォルトのアプリケーションです。若い世代のマイナーガベージコレクションは複数のスレッドを利用しますが、古い世代のメジャーガベージコレクションは単一のスレッドを使用します。
シリアルGCと同様に、パラレルガベージコレクターにも「stopthe worldイベント」があり、現在ガベージコレクションを処理しているアプリケーションを一時停止します。 このタイプのコレクターは、長い休止が必要になる可能性のある多くの作業を行う場合に適しています。
並列古いGC
これはJava 7u4以降の並列GCの古いバージョンです。若い世代と古い世代の両方でマルチスレッドプロセッサとして動作する点が、並列GCとは少し異なります。このコレクターを使用することで、プログラマーはガベージコレクターのスレッド数を制御し、最大停止時間目標を指定し、最大スループット目標を規定できます。
CMS(コンカレントマークスイープ)GC
CMS ガベージ コレクター (同時低停止コレクターとも呼ばれる) は、ガベージ コレクションをノンストップで処理する機能を備えています。
さらに、マイナーガベージコレクションでのアクティビティは、複数のスレッドプロセスで実行されます。 マルチスレッドプロセスは、より多くのCPUスペースを使用するため、他のガベージコレクターよりもアプリケーションでうまく機能します。 また、CPUスペースが多いほどパフォーマンスが向上する場合は、並列コレクターよりもCMSガベージコレクターの方が適しています。 ただし、状況によっては、アプリケーションのパフォーマンスが低下する場合があります。
G1(ガベージファースト)GC
G1ガベージコレクターは、並列および同時パフォーマンスの点でCMSガベージコレクターと同様に機能します。 ただし、これは主にCMSガベージコレクターJDK1.7を置き換え、GCの分野でより良いエクスペリエンスをもたらすために作成されました。 G1は、マークスイープアルゴリズムを使用してガベージコレクションを実行します。 パフォーマンス効率が高いため、G1は最終的にCMSに取って代わる可能性があります。
メモリ ヒープを均等なサイズの領域に分割し、複数のスレッドを使用してスキャンします。
「ガベージ ファースト」という用語は、メモリ システムに空き領域を増やすために最初に空き領域を識別する G1 のガベージ コレクション アクティビティに由来します。
イプシロンGC
EpsilonはJDK 11のアップデートで、パッシブ型、つまり非オペレーショナル型のガベージコレクタとしてリリースされました。メモリ割り当てのみを実行し、Javaヒープメモリが枯渇するとJVMがシャットダウンするため、メモリ回収は実行できません。さらに、Epsilonガベージコレクタは、メモリ不足でクラッシュするアプリケーションにも効率的に対応できます。
Epsilonは、ガベージコレクターによって引き起こされる非効率性を測定、制御、そして排除することで、アプリケーションのパフォーマンス向上を目指します。また、メモリ不足が発生するたびに表示することで、ガベージコレクターがアプリケーションのスムーズな実行にどのように影響するか、そしてメモリしきい値の上限値についてより深く理解できるようにします。アプリケーションのパフォーマンスを最適化したいユーザーにとって、Epsilonガベージコレクターは現実的な選択肢です。
シェナンドアGC
ShenandoahはJDK12の一部としてリリースされました。これにより、Javaプログラムがバックグラウンドで操作を続行できるようにしながら、一時停止時間を短縮することで、ガベージコレクターのエクスペリエンスが向上しました。 さらに、Shenandoahは、超低休止時間GCを使用して、すべてのライブオブジェクトを正常にマークし、メモリスペースの同時圧縮を生成します。
G1とは異なり、Shenandoahのガベージコレクションサイクルはアプリケーションと並行して実行されます。ライブオブジェクトの圧縮と再配置のためにアプリケーションを一時停止する必要はありません。そのため、CPUへの負荷が高くなります。
Shenandoahは、すべてのヒープオブジェクトに転送ポインタを追加することでオブジェクトへのアクセスを制御し、分割された領域内でのオブジェクトの移動を容易にします。また、アプリケーションスレッドと並行してヒープを積極的に圧縮する機能も、Shenandoahを他のガベージコレクターとは一線を画しています。
Zガベージコレクター (ZGC)
ZGCは、低遅延が必要なアプリケーションや、巨大なヒープ(数テラバイト)を使用するアプリケーションに最適です。 色付きのポインターを使用して、スレッドの実行中に操作を実行することにより、ヒープの使用状況を追跡します。 ZGCは使いやすく、拡張性に優れています。 ガベージコレクションアクティビティを実行するときにJavaアプリケーションを実行できます。
その短い休止時間は、他のガベージコレクターに比べて大幅な改善をもたらします。 このコレクターによるパーティションはサイズが異なります。 ZGCは、次のXNUMXつのフェーズでマーキングを行います。
- 遊撃手フェーズ: このフェーズでは、ZGCはGCルートを調べて、ヒープが大きくなるにつれて一時停止が増加しないことを確認します。
- 同時フェーズ: オブジェクトグラフをスキャンし、到達可能なオブジェクトの色付きのポインタとマークを調べます。
- 再配置フェーズ: ライブオブジェクトを移動してヒープメモリを解放します。
Javaメモリ管理
Javaのメモリ管理とは、オブジェクトの割り当てと解放を行うプロセスです。これはプログラマーの直接的な介入を必要としない自動プロセスです。
しかし、このプロセスで全てが保証されるわけではありません。つまり、クラッシュしない高性能なプログラムを書くには、プログラマーはJavaのメモリ管理の仕組みを理解する必要があります。たとえクラッシュしたとしても、プログラマーはデバッグ方法を知っているはずです。メモリ管理によって、パフォーマンスに影響を与える可能性のあるメモリリークを防ぐことができます。
Java メモリ管理の中心的な概念は、JVM メモリ構造とガベージ コレクターの動作です。
ガベージコレクターの動作について包括的に説明したので、JVMのメモリ構造を見てみましょう。
この試験は is JVM Mエモリー S構造?
JVMは、プログラム実行中に使用される様々なランタイムデータ領域を定義します。一部の領域はJVMによって作成され、他の領域はプログラムで使用されるスレッドによって作成されます。JVMによって作成されたメモリ領域は、JVMの終了時に破棄されます。スレッドによって作成されたデータ領域も同様です。
Java メモリ領域は、ヒープ、メソッド領域、JVM スタック、ネイティブ メソッド スタック、PC レジスタなど、さまざまな部分で構成されます。
各領域は、プログラムを正常に実行することを最終目標として、特定のタスクを実行します。
効果的なガベージコレクションによるJavaパフォーマンスの向上
Javaのガベージコレクションは自動プロセスですが、スキルを向上させたいプログラマーは、ガベージコレクションの仕組みを学ぶ必要があります。これにより、Javaヒープメモリを適切に設定および管理することで、ガベージコレクションのアクティビティを最適化できるようになります。
また、最適なJavaアプリケーションのパフォーマンスを得るには、ガベージコレクションを監視することが不可欠です。 これにより、ユーザーは中断やダウンタイムなしでプログラムを簡単に実行できます。
Javaのガベージコレクションは、開発者の作業を非常に楽にしてくれる裏方機能の一つですが、その効果は限定的です。メモリ管理は自動的に行われますが、その仕組みを理解することが、特に大規模なアプリケーションにおいて、応答性と効率性に優れたアプリケーションを構築する鍵となります。
適切なガベージコレクターを選択し、適切にチューニングし、ストップ・ザ・ワールド(STO)による一時停止やメモリリークといった問題に注意することで、パフォーマンスに大きな違いが生まれます。低レイテンシのシステムでも高スループットのサービスでも、GC戦略を理解することはコードと同じくらい重要です。
私たちのブログを購読する
このような記事をあなたの受信箱に直接お届けします