前回の記事では、JVM メモリ モデルに関する関連知識を紹介しましたが、実際には、実行時の定数プールの動的挿入やダイレクト メモリなど、さらに詳しく紹介できる内容がいくつかあります。前回のブログを改善する時間です。今日は、JVM のガベージ コレクション戦略をいくつか紹介します。
1. Finalize() メソッド
GC 戦略を紹介する前に、まず GC の Finalize メソッドを紹介しましょう。オブジェクトに参照がない場合、通常、オブジェクトはリサイクルされますが、オブジェクトがリサイクルされる前に、一部のリソースを閉じる、またはリサイクルされないようにオブジェクトを復活させるなど、いくつかの操作を実行したい場合はどうすればよいでしょうか。この場合は、ファイナライズメソッドが使用されます。 Finalize メソッドは Object クラスで定義されたメソッドであり、どのオブジェクトにもこのメソッドがあることを意味します。ただし、このメソッドは一度しか呼び出されず、オブジェクトが復活した後に再び死亡した場合、オブジェクトが 2 回目にリサイクルされるときに Finalize メソッドは呼び出されず、優先度は比較的低く、呼び出される保証はありません。が実行されるため、finalize メソッドの使用はお勧めできません。まとめると、特徴は 3 つあります: ①、GC は以前に呼び出されています。 ②.一度だけ呼び出されます。 ③. 信頼性が低く、確実に実行されるとは限りません。 の使用は推奨されません。 Finalize の使用方法については、次のコードを参照してください。
1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 Thread.sleep(5000); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 }
このコードを実行した結果は次のとおりです。
Finalize メソッドの実行後、テスト オブジェクトが再アクティブ化されることがわかります。 , したがって、まず、i am が生きていると印刷されます。しかし、2 回目の GC 中に、finalize メソッドが実行されなかったため、2 番目に、i am Dead が出力されました。前述したように、finalize は優先度が低く、信頼性が低いので、Thread.sleep(5000) がない場合は、コードと結果を見てみましょう:
1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 //不执行睡眠操作,Thread.sleep(5000); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 //不执行睡眠操作,Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 }
実行結果は次のとおりです。
ここでは非常に簡単です。finalize メソッドの優先順位が比較的低いことが明らかにわかります。 この例についての考察: この例の最初のコードは、「Java 仮想マシンの徹底理解」のコードを参照して実装されていますが、常に 2 つの疑問があると感じています: テスト オブジェクトはなぜ存在するのか静的に変更されたメンバー変数として?静的変更の場合はメソッド領域があり、メソッド領域での GC 効果は通常あまり良くありません。もう1つはメンバー変数の形で存在するため、finalizeをリサイクルした際に現在のオブジェクト自体のリサイクルが反映されないので、この例はあまり良くない気がします。2. 参照カウント方法
参照カウント方法は、現在一般的には使用されていない初期の GC リサイクル アルゴリズムです。その主な考え方は次のとおりです。 各オブジェクトは、初期値 0 の参照カウンターを維持します。 、オブジェクトが参照されると、オブジェクトの参照カウンタは 1 増加します。参照されない場合、オブジェクトの参照カウンタは 1 減少します。オブジェクトの参照カウンタが 0 になると、そのオブジェクトは使用可能とみなされます。リサイクルされます。この方法を使用する場合の利点と欠点は明らかです。利点は、実装が簡単であることと、効率が高いことです。欠点は、循環参照が発生してメモリ オーバーフローが発生する可能性があることです。
3. マークアンドスイープ法
マークアンドスイープ法は、その名の通り「マーク」と「クリア」の 2 段階に分かれています。 最初にすべての生存者をマークします マークが完了すると、マークされたすべてのオブジェクトが均一に消去されます。では、オブジェクトがリサイクル可能かどうかを判断するにはどうすればよいでしょうか? GC 中、走査は一連の GC ルート ルート ノードから開始されます。走査中に移動するパスは参照チェーンと呼ばれます。オブジェクトに GC ルートに関連する参照チェーンがない場合、そのオブジェクトは使用できません。リサイクル可能と判断されるこのアルゴリズムは、ルート探索アルゴリズムとも呼ばれます。では、どのオブジェクトが GC ルート オブジェクトになることができるのでしょうか? Java 言語では、GC ルートとして使用できるオブジェクトには次の 4 種類があります:
GC ルートの使用。J ローカル メソッド スタック内の jni の引用オブジェクト (つまり、ネイティブ メソッド)- 次のようにアルゴリズム図をクリアします:
注: この記事の GC リサイクル アルゴリズムの図は次のとおりです。ネチズンの記事(ここをクリック)から転送したものです。ネチズンの写真の内容も元の作品と一致していますが、色が異なります。
4. 新世代のコピー方法 コピー方法の基本的な考え方は次のとおりです:
メモリを同じサイズの 2 つのブロックに分割し、GC 中に一度に 1 つのブロックのみを使用します。残っているすべてのオブジェクトは、別のエリアに移動してそのメモリを消去するたびにコピーされます。
これらはすべてメソッド領域とスタック内の参照オブジェクトです。コピー方式の利点は、実装が簡単、再利用が速い、メモリの断片化がないことです。ただし、一度に使用されるブロックは 1 つだけであるため、メモリ使用率は低くなります。レプリケーション アルゴリズムの概略図は次のとおりです。
関連する推奨事項:
jvm ガベージ コレクション アルゴリズム
以上がJAVA仮想マシン学習メモ:JVMメモリモデルにおけるガベージコレクション手法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。