Javaでのガベージコレクション  

Javaでのガベージコレクション

Javaでのガベージコレクションは、コーディングの世界ではおなじみの用語です。 Javaプログラミング言語を学ぶときにそれに出くわすでしょう。 Javaメモリ管理に組み込まれているため、ガベージコレクタはJavaの重要な機能のXNUMXつです。 重大なエラーを防ぎ、プログラマーが不要なオブジェクトを気にせずに新しいオブジェクトを作成できるようにします。

ただし、ガベージコレクション(GC)を実行するバックグラウンドスレッドは予測できない時間に実行されるため、アプリケーションのパフォーマンスが低下したり、速度が低下したりして、不要な遅延が発生する可能性があります。 したがって、開発者は、プログラムの実行時に妨げられないようにするために使用する適切なガベージコレクターを明確に理解する必要があります。

この記事では、Javaでのガベージコレクションに伴う詳細について説明します。 また、ガベージコレクションの主な利点と、ガベージコレクションがどのように機能するかについての簡単な説明が含まれており、開発者と管理者がアプリケーションでガベージコレクションをより簡単に使用できるようになります。

内容

ガベージコレクションとは何ですか?

ガベージコレクションは、未使用のランタイムメモリを自動的に再利用するプロセスです。 つまり、未使用のオブジェクトは自動的に破棄されるため、開発者はメモリの割り当てや割り当て解除を気にせずに新しいオブジェクトを作成できます。

プログラマーがオブジェクトを手動で作成および破棄するCやC++などの言語では、冗長オブジェクトを管理して絶えず破棄するのは難しい場合があります。 保存されている不要なオブジェクトが多すぎると、システムのメモリが最新のオブジェクトを効率的に割り当てることができない場合があります。

さらに、手動で割り当てると、特にプログラマーが不要なメモリを解放しない場合や、実行中のコードでメモリヒープ内のオブジェクトにアクセスできない場合に、システムがメモリリークの影響を受けやすくなります。

Javaプログラムはで実行されます Java仮想マシン (JVM)バイトコードの形式。 JVMは、バイトコードを解釈してプログラムを実行し、ヒープスペースまたはプログラムに割り当てられたメモリ部分にオブジェクトを作成できるようにします。

新しいオブジェクトの作成と解放は、一部のオブジェクトが完全に不要になるまで続きます。 その時点で、ヒープにはXNUMXつのタイプのオブジェクトが含まれています。これらは次のように記述できます。

デッド:不要なオブジェクトまたは使用されなくなったオブジェクト。                      

ライブ: 使用中および参照中のオブジェクト。

ガベージコレクションの利点は何ですか?

多くのプログラマーは、明示的なストレージ再利用のパフォーマンスは、メモリ管理における自動ガベージコレクションよりも優れていると考えています。 ただし、いくつか 研究 ガベージコレクターの下で十分に開発されたシステムは、明示的な割り当て解除を使用したシステムよりも優れた結果を生み出すことを示しました。 ガベージコレクションの利点のいくつかを次に示します。

  • 自動割り当て解除は、開発者が手動でメモリを解放し、システムの書き込み性を高め、開発の時間とコストを節約するのに役立ちます。
  • 管理対象ヒープにオブジェクトを割り当てるのは効率的です。
  • オブジェクトがメモリ割り当てを使い果たしたときに、別のオブジェクトに割り当てられたメモリを使用できないように、メモリの安全性を提供します。
  • 使用されなくなったオブジェクトを再利用してメモリをクリアすることにより、ガベージコレクションはメモリを解放し、将来使用できるようにします。 最初はクリーンなコンテンツがあるため、開発者はすべてのフィールドを開始する必要はありません。
  • ガベージコレクションにより、プログラムの効率が保証されます。

ガベージコレクションはJavaでどのように機能しますか?

Javaのガベージコレクションは、価値のあるオブジェクトと価値のないオブジェクトを識別し、未使用のオブジェクトを排除することによってヒープメモリを実行する自動操作です。 プログラムの実行中のコードが到達できないオブジェクトは、解放して使用できるメモリを占有します。

他の言語とは異なり、JVMはJavaで不要なデータを管理するため、プログラマーはオブジェクトによって実行されるすべてのアクティビティを制御する必要はありません。 JVMはガベージコレクターを指示します。 したがって、ヒープが大きくなるたびに、JVMはクリーンアッププロセスを自動的に実行します。

次に、XNUMXつの基本的な手順でガベージコレクションがどのように行われるかを確認します。

  1. マーク: これは、ガベージコレクターが使用済みオブジェクトと未使用オブジェクトを識別する段階です。 参照されていないオブジェクトは、削除待ちとしてマークされます。 アプリケーションが参照を保持するオブジェクトは引き続き有用であり、今後も残ります。
  2. 掃く: この段階では、参照されていないオブジェクトをクリアしてスペースを解放します。 また、ガベージコレクターは、ライブオブジェクトとポインターを空の領域に保存します。 最後に、参照されていないオブジェクトを保持しているヒープメモリが解放され、新しいオブジェクト用のスペースが作成されます。
  3. コンパクト: これは、フラグメント化されたオブジェクトをヒープの先頭から再配置して、新しく割り当てられたオブジェクト用のスペースを作成する最後のステップです。 再配置のための空きスペースは、ガベージコレクターによってクリアされた不要なメモリに起因し、プログラムの実行時に効率的なパフォーマンスをもたらします。

マーク、スイープ、およびコンパクトアルゴリズムは、最も基本的なガベージコレクションレベルです。 ただし、ほとんどのオブジェクトは短命であるため、フルマーク、スイープ、およびコンパクトプロセスの実行に失敗する可能性があります。

その結果、プログラマーは、すべての短期間のオブジェクトを確実に管理するために、より効率的な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種類のアクティビティが含まれます。

マイナーまたはインクリメンタルガベージコレクション

この操作は若い世代で実行され、ヒープメモリで見つかった到達不能なオブジェクトをクリアします。

メジャーまたはフルガベージコレクション   

メジャーガベージコレクションは、マイナーガベージコレクションによってクリアされず、古いヒープメモリにコピーされたオブジェクトを検索して削除するために実行されます。 生き残ったオブジェクトは、新しいオブジェクトを順番に配置するために圧縮されます。 このフェーズでは、ガベージコレクションの頻度は若い世代よりも少なくなります。 また、このパーティションでのガベージコレクションの頻度は低くなります。 

参照されていないオブジェクト

参照されていないオブジェクトは、プログラマーにとって価値がなくなったオブジェクトを示します。 この場合、すべてのオブジェクトから基準点を引いたものは不要と見なされます。 ヒープメモリにスペースを作成するために、ガベージコレクタはこれらの参照されていないオブジェクトを破棄し、メモリを再利用して圧縮し、新しい割り当てのためにスペースを準備します。

オブジェクトを参照しないようにするにはどうすればよいですか?

プログラマーは不要なオブジェクトを破棄する責任はありませんが、不要になったオブジェクトを到達不能にする必要があります。 参照されていないオブジェクトが削除されない場合、それらはヒープメモリをいっぱいにし、プログラムのパフォーマンスを妨害します。 これらは通常、メモリリークと呼ばれます。 オブジェクトへの参照を省略してガベージコレクションの対象にすることができる簡単なトリックがあります。 それらが含まれます:

  • 参照変数の再割り当て。
  • 参照をnullにします。
  • 匿名オブジェクトを使用します。

ガベージコレクションのルーツ

ガベージコレクションのルートは、ガベージコレクションプロセスにおける一意のオブジェクトです。 これらは主にガベージコレクションの開始点であり、JVMによって参照されます。 したがって、直接または間接的に参照される他のすべてのオブジェクトがガベージコレクションされないようにします。 すべてのアプリケーションまたはプログラムは、ツリーの他の部分に到達するためにルートにアクセスできる必要があります。 以下は、JavaのXNUMXつの主要なガベージコレクションルートです。

  1. ローカル変数: スレッドのスタックがそれらを接続している限り、これらは存続します。
  2. アクティブなJavaスレッド: アクティブなJavaスレッドは、ライブスレッドと見なされるため、ガベージコレクションのルートリストに加わります。
  3. 静的変数: 静的変数はクラスに参照されます。 したがって、これらのガベージコレクターのルートは、クラスがロードされるときにクリアランスの対象にはなりません。 クラスはガベージコレクションされ、参照されているすべての静的変数を削除できます。 これは、一般にクラスローダーまたはアプリケーションサーバーを使用する場合に不可欠です。
  4. JNIリファレンス: これらは、ガベージコレクターがネイティブコードとして参照されている到達不能オブジェクトを見つけるのに役立つJavaオブジェクトです。 JNI参照は、これらのタイプのオブジェクトを公開し、JVMがそれらを処理できるようにします。 ネイティブコードとして参照されているオブジェクトが識別されない場合、JVMはそれらのオブジェクトでガベージコレクションを実行できない可能性があります。

Java仮想マシンのガベージコレクターのタイプ

ガベージコレクションは、参照されていないオブジェクトをヒープから削除し、新しく設計されたオブジェクトに十分なスペースを提供することにより、Javaメモリで重要な役割を果たします。 JVMは異なります ガベージコレクターの種類。 それぞれの包括的な詳細は次のとおりです。

シリアルGC

シリアルガベージコレクターは、シングルスレッドプロセスで実行されるアプリケーション用に明示的に開発されました。 シリアルGCは、すべてのマルチスレッドアプリケーションをブロックして、アクティビティを実行するときにXNUMXつのスレッドでシリアルに収集を実行します。 ガベージコレクションサイクルごとに、シリアルガベージコレクターはメモリを圧縮して、メモリの断片化を回避します。

一時停止時間が短いアプリケーションは、ガベージコレクションに干渉する可能性があるため、お勧めしません。 この干渉は通常、シリアルGCが一時停止アプリケーションを開始している間にアプリケーションが通常のアクティビティを再開したときに発生します。これは一般に「ワールドイベントの停止」として知られています。

パラレルGC     

並列GCは、マルチスレッドプロセッサを介してヒープメモリシステムを実行し、通常はJVMでのアクティビティのデフォルトのアプリケーションであるため、大規模なデータで効率的に機能します。 若い世代のマイナーガベージコレクションは複数のスレッドを使用しますが、古い世代のメジャーガベージコレクションは単一のスレッドを使用します。

シリアルGCと同様に、パラレルガベージコレクターにも「stopthe worldイベント」があり、現在ガベージコレクションを処理しているアプリケーションを一時停止します。 このタイプのコレクターは、長い休止が必要になる可能性のある多くの作業を行う場合に適しています。

パラレルオールドGC

これは、Java7u4以降の古いバージョンの並列GCです。 並列GCとは少し異なります。これは、若い世代と古い世代のマルチスレッドプロセッサを実行するためです。 このコレクターを使用すると、プログラマーはガベージコレクタースレッドの数を制御し、最大休止時間の目標を指定し、最大スループットの目標を指定できます。

CMS(コンカレントマークスイープ)GC

CMSガベージコレクターは、コンカレントローポーズコレクターとも呼ばれ、ガベージコレクションをノンストップで処理する機能を意味します。

さらに、マイナーガベージコレクションでのアクティビティは、複数のスレッドプロセスで実行されます。 マルチスレッドプロセスは、より多くのCPUスペースを使用するため、他のガベージコレクターよりもアプリケーションでうまく機能します。 また、CPUスペースが多いほどパフォーマンスが向上する場合は、並列コレクターよりもCMSガベージコレクターの方が適しています。 ただし、状況によっては、アプリケーションのパフォーマンスが低下する場合があります。

G1(ガベージファースト)GC

G1ガベージコレクターは、並列および同時パフォーマンスの点でCMSガベージコレクターと同様に機能します。 ただし、これは主にCMSガベージコレクターJDK1.7を置き換え、GCの分野でより良いエクスペリエンスをもたらすために作成されました。 G1は、マークスイープアルゴリズムを使用してガベージコレクションを実行します。 パフォーマンス効率が高いため、G1は最終的にCMSに取って代わる可能性があります。

メモリヒープを同じサイズの領域のセットに分割し、複数のスレッドを使用してそれらをスキャンします。

その名前「ガベージファースト」は、G1のガベージコレクションアクティビティに由来しています。これには、最初に空の領域を特定して、メモリシステムにより多くの空き領域を生成することが含まれます。

イプシロンGC

EpsilonはJDK11のアップデートであり、パッシブまたは非動作のガベージコレクタとしてリリースされました。 メモリ割り当てを実行するだけですが、Javaヒープメモリが使い果たされた後にJVMがシャットダウンするため、メモリ割り当てを取得できません。 さらに、Epsilonガベージコレクターは、メモリが不足してクラッシュするアプリケーションで効率的に動作できます。

ガベージコレクターによって引き起こされる非効率性を測定、制御、および排除することにより、アプリケーションのパフォーマンスを向上させることを目指しています。 また、ガベージコレクターがアプリケーションのスムーズな実行とメモリのしきい値にどのように影響するかを理解するために、ガベージコレクターがなくなるたびに表示します。 アプリケーションのパフォーマンスを最適化したいユーザーにとって、Epsilonガベージコレクターは実行可能な選択肢です。

シェナンドアGC

ShenandoahはJDK12の一部としてリリースされました。これにより、Javaプログラムがバックグラウンドで操作を続行できるようにしながら、一時停止時間を短縮することで、ガベージコレクターのエクスペリエンスが向上しました。 さらに、Shenandoahは、超低休止時間GCを使用して、すべてのライブオブジェクトを正常にマークし、メモリスペースの同時圧縮を生成します。

G1とは異なり、Shenandoahのガベージコレクションサイクルはアプリと同時に実行されます。 ライブオブジェクトを圧縮して再配置するためにアプリケーションを一時停止する必要はありません。 これにより、CPUがより集中的になります。

Shenandoahは、すべてのヒープオブジェクトに転送ポインターを追加することでオブジェクトへのアクセスも制御し、パーティション化された領域内でオブジェクトを簡単に移動できるようにします。 また、アプリケーションスレッドと並行してヒープを積極的に圧縮する機能により、他のガベージコレクターとは一線を画しています。

Zガベージコレクター

ZGCは、低遅延が必要なアプリケーションや、巨大なヒープ(数テラバイト)を使用するアプリケーションに最適です。 色付きのポインターを使用して、スレッドの実行中に操作を実行することにより、ヒープの使用状況を追跡します。 ZGCは使いやすく、拡張性に優れています。 ガベージコレクションアクティビティを実行するときにJavaアプリケーションを実行できます。

その短い休止時間は、他のガベージコレクターに比べて大幅な改善をもたらします。 このコレクターによるパーティションはサイズが異なります。 ZGCは、次のXNUMXつのフェーズでマーキングを行います。

  1. 遊撃手フェーズ: このフェーズでは、ZGCはGCルートを調べて、ヒープが大きくなるにつれて一時停止が増加しないことを確認します。
  2. 同時フェーズ: オブジェクトグラフをスキャンし、到達可能なオブジェクトの色付きのポインタとマークを調べます。
  3. 再配置フェーズ: ライブオブジェクトを移動してヒープメモリを解放します。

Javaメモリ管理

Javaメモリ管理は、オブジェクトの割り当てと割り当て解除のプロセスです。 これは、プログラマーの直接の介入を必要としない自動プロセスです。

ただし、自動プロセスがすべてを保証するわけではありません。 つまり、プログラマーは、クラッシュしない高性能ベースのプログラムを作成するために、Javaのメモリ管理がどのように機能するかを知る必要があります。 それらがクラッシュした場合でも、プログラマーはデバッグ方法を知っています。 メモリを管理することで、パフォーマンスに影響を与える可能性のあるリークを防ぎます。

Javaメモリ管理の中心的な概念は、JVMメモリ構造とガベージコレクタの動作です。

ガベージコレクターの動作について包括的に説明したので、JVMのメモリ構造を見てみましょう。

JVMメモリ構造とは何ですか?

JVMは、プログラムの実行中に使用されるさまざまな実行時データ領域を定義します。 一部の領域はJVMによって作成され、他の領域はプログラムで使用されるスレッドによって作成されます。 JVMによって作成されたメモリ領域は、JVMが終了すると破棄されます。 スレッドによって作成されたデータ領域にも同じことが当てはまります。

Javaメモリ領域は、ヒープ、メソッド領域、JVMスタックネイティブメソッドスタック、PCレジスタなどのさまざまな部分で構成されています。

各領域は特定のタスクを実行し、最終的な目標はプログラムを正常に実行することです。

まとめ

Javaでのガベージコレクションは自動プロセスですが、スキルを向上させたいプログラマーは、ガベージコレクションがどのように機能するかを学ぶ必要があります。 これは、Javaヒープメモリが適切に構成および管理されていることを確認することにより、ガベージコレクションアクティビティを最適化するのに役立ちます。

また、最適なJavaアプリケーションのパフォーマンスを得るには、ガベージコレクションを監視することが不可欠です。 これにより、ユーザーは中断やダウンタイムなしでプログラムを簡単に実行できます。