Javaでは、メモリ管理には、メモリの割り当て(Javaオブジェクトを作成するとき)とメモリリサイクルの2つの側面が含まれます。作業の両方の側面はJVMによって自動的に完了し、Javaプログラマーの学習の難しさを軽減し、C/C ++のような直接動作メモリの危険を回避します。しかし、それはまさに、多くのJavaプログラマーがメモリの割り当てに関心を持たなくなったため、メモリ管理がJVMによって完全に処理され、多くのプログラムが非効率的で消費されるメモリになるためです。したがって、Javaプログラマーは、より効率的なプログラムを作成し、限られたメモリを最終的に使用するために、最終的にJVMを理解する必要があります。
1.Javaの記憶状態
まず、コードを例として書きましょう。
person.java
パッケージテスト; Import java.io.serializable; public classの人はシリアル化可能{static final long serialversionuid = 1l;文字列名; //人の名前の名前。 // friends public person(){} public person(string name){super(); this.name = name; }} test.java
パッケージテスト;パブリッククラステスト{public static void main(string [] args){person p1 = new person( "kevin");人P2 =新しい人(「雨」);人P3 =新しい人( "Sunny"); P1.Friend = P2; P3 = P2; p2 = null; }}上記の主な側面にオブジェクト参照を描画する場合、上記のJavaはメインメソッドから始まるオブジェクト参照図に描画する場合、これはこのようなものです(頂点はオブジェクトと参照であり、指示されたエッジは参照関係です):
プログラムが実行されると、指示されたグラフと見なされた後、3つのタイプに分けることができます。
1)達成可能な状態:オブジェクトが作成された後、複数の参照変数がそれを参照します。指示されたグラフでは、開始頂点からオブジェクトにナビゲートでき、アクセス可能な状態にあります。
2)回復可能な状態:プログラム内のオブジェクトがそれを参照する参照変数がなくなった場合、最初に修復可能な状態に入り、現時点では、指向グラフの開始頂点からオブジェクトに移動できません。この状態では、システムのごみ収集メカニズムは、オブジェクトが占めるメモリをリサイクルする準備ができています。リサイクルする前に、システムはリソースをクリーンアップするためにfinalize()メソッドを呼び出します。リソースがソートされた後に複数の参照変数が再生されると、オブジェクトは再びアクセス可能な状態になります。それ以外の場合は、到達不能な状態に入ります。
3)到達不可能な状態:オブジェクトのすべての関連付けが遮断され、システムがリソースをクリーンアップするためにfinalize()メソッドを呼び出しても、オブジェクトに到達可能な状態にならない場合、オブジェクトは参照を永久に失い、到達不可能な状態になり、システムはオブジェクトが占有するリソースを真にリサイクルします。
上記の3つの状態の遷移図は次のとおりです。
2。4Javaによるオブジェクトへの参照
1)強力な参照:オブジェクトを作成し、このオブジェクトを変数に直接割り当てます。システムリソースがどれほどタイトであっても、将来再び使用されなくても、強力な参照オブジェクトがリサイクルされることはありません。
2)ソフトリファレンス:softreferenceクラスを通じて実装された例:softreference <serson> p = new softreference <serson>(new person>( "Rain"));、記憶が非常にきつくなったら、他の時にリサイクルされ、それを使用する前に、それがリサイクルされているかどうかを判断する必要があります。
3)弱い参照:WeakReferenceクラスを通じて実装、例:weakreference <serson> p = new weakReference <serson>(new Person( "Rain"));メモリで十分かどうかに関係なく、システムはごみ収集中に間違いなくリサイクルされます。
4)仮想引用:単独で使用することはできません。主に、収集されたガベージであるオブジェクトの状態を追跡するために使用されます。 Phantomreferenceクラスとリファレンスキューリファレンスキュークラスを通じて実装されています。
パッケージテスト; import java.lang.ref.phantomreference; Import java.lang.referencequeue; public class test {public static void main(string [] args){//オブジェクトパーソン= new person( "sunny"); //リファレンスキューリファレンス<パーソン> rq = new ReferenceQueue <Person>()を作成します。 //仮想リファレンスを作成するには、Person Objectへのこの仮想リファレンスを<Person> pr = new Phantomreference <serson>(Person、RQ); //参照変数と人のオブジェクトを解決する参照者= null; //仮想参照によって参照されるオブジェクトを出してみてください//プログラムは仮想リファレンスを介して参照オブジェクトにアクセスできないため、ここの出力はnull system.out.println(pr.get()); //強制ガベージコレクションSystem.gc(); System.RunFinalization(); //仮想リファレンスのオブジェクトがリサイクルされると、仮想参照は参照キューに入力します//参照を使用して、最初にキューのキューに入力してprと比較し、true system.out.println(rq.poll()== pr)を出力します。 }}実行結果:
3。JavaGarbage Collectionメカニズム
実際、Java Garbage Collectionは主に2つのことを行います。1)メモリリサイクル2)解体
3.1ガベージ収集アルゴリズム
1)シリアルリサイクル(1つのCPUのみ)と並列リサイクル(複数のCPUが有用です):シリアルリサイクルとは、システムがどれだけ多くのCPUを持っていても、ガベージコレクション操作を実行するのは常に1つのCPUだけです。並列リサイクルとは、リサイクル作業全体を複数の部分に分割することを意味し、各部品が1つのCPUによって責任を負うため、複数のCPUを並行してリサイクルできます。並列リサイクルは実行において非常に効率的ですが、複雑さを高め、メモリのランダム増加など、いくつかの副作用もあります。
2)同時実行とアプリケーションの停止:名前が示すように、そのごみ収集方法は、ガベージコレクションの実行中にアプリケーションサスペンションを引き起こします。同時実行のガベージがアプリケーションとの競合を解決する必要があるため(ガベージ収集プロセス中にアプリケーションがオブジェクトを変更する可能性があるため、同時実行の同時実行のごみ収集はアプリケーションを一時停止させませんが、ガベージ収集の同時実行のシステムオーバーヘッドは、停留所のものよりも高く、実行される場合はよりヒープメモリを必要とします。
3)圧縮と非抑制とコピー:
compression圧縮(マーク圧縮=マーククリア +圧縮)をサポートするゴミコレクターは、すべての到達可能なオブジェクトを一緒に再配置し、以前に占められたすべてのメモリをリサイクルして、メモリの断片化を削減します。
comprespされていないガベージコレクター(マーククリア)を2回横断する必要があります。最初にすべての到達可能なオブジェクトに最初にアクセスし、それらを到達可能な状態としてマークするとき。メモリ領域全体を促進し、到達可能な状態とマークされていないオブジェクトをリサイクルする2回目。このリサイクル方法は圧縮されておらず、余分なメモリを必要としませんが、2つのトラバーサルが必要な場合に断片化が生成されます。
coperガベージコレクターをコピーします:ヒープメモリを2つの同一のスペースに分割し、関連する各到達可能なオブジェクトにルートからアクセスし(前の指示グラフの開始頂点と同様)、スペースAのすべての到達可能なオブジェクトをスペースBにコピーし、一度にスペースAをリサイクルします。このアルゴリズムの場合、すべての到達可能なオブジェクトにアクセスし、すべての到達可能なオブジェクトをコピーして、到達不能なオブジェクトをまったく無視してスペース全体を直接リサイクルするだけで、スペースを通過するコストは小さいですが、膨大なコピーコストとメモリが必要です。
3.2ヒープメモリの世代リサイクル
1)世代のリサイクルの基礎:
offictionオブジェクトの生存時間の長さ:ほとんどのオブジェクトは若い期間中にリサイクルされます。異なる世代はさまざまなごみリサイクル戦略を採用します:新しい(短い生存時間)古い(長期生存時間)オブジェクト間の参照はめったにありません
2)ヒープメモリの生成:
①世代:若い世代:
Recyclingメカニズム:オブジェクトの数が小さいため、複製とリサイクルが使用されます。
consolidation統合エリア:1つのエデンエリアと2つの生存地域で構成されています。 2つの生存地域は同時に、1つはオブジェクトを保存するために使用され、もう1つは空です。若い世代のガベージコレクションが実行されるたびに、エデンとそれからアクセス可能なオブジェクトがエリアにコピーされ、長寿命のものの一部が老年にコピーされ、エデンと空間からコピーされ、最終的に宇宙から宇宙から元のオリジナルが宇宙から宇宙になります。
ⅲオブジェクトソース:ほとんどのオブジェクトは最初にEdenエリアに割り当てられ、いくつかの大きなオブジェクトは古い世代に直接割り当てられます。
remycycycyclingリサイクル頻度:ほとんどの若い世代のオブジェクトは到達不能な状態にすばやく入るため、リサイクル周波数は高く、リサイクル速度は高速です。
old世代:
Recyclingメカニズム:マーク圧縮アルゴリズムを使用して回復します。
ⅱオブジェクトのソース:1。大きなオブジェクトは老齢に直接入ります。
2。若い世代の長期生存時間を持つリーチ可能なオブジェクトのリサイクル頻度:死ぬオブジェクトはほとんどないため、実行頻度は高くなく、完了するのに長い時間がかかります。
③世代の世代:
urpose:クラス、方法、その他の情報をロードするために使用されます。デフォルトは64mで、リサイクルされません。 Object Source:eg:hibernateやSpringのようなフレームワークの場合は、AOPの動的生成クラスのように多数のダイナミックプロキシクラスを生成することが多いため、より永続的な生成メモリが必要です。そのため、冬眠をデバッグするときに、java.lang.outofmemoryerror:permgenスペースエラーに遭遇することがよくあります。これは、永続的な生成メモリの疲労によって引き起こされるエラーです。
crecy頻度:リサイクルされません
3.3一般的なゴミコレクター
1)シリアルリサイクル(1つのCPUのみが使用されます):Young Generationはシリアルコピーアルゴリズムを使用します。古い世代は、シリアルマーク圧縮アルゴリズムを使用します(3つの段階:マークマーク - クリアスイープ - コンパクトコンパクト)、プログラムはリサイクル期間中に一時停止されます。
2)並列リサイクル:若い世代に使用されるアルゴリズムは、シリアルリサイクルと同じですが、マルチCPU並列処理のみを追加します。古い世代の処理は、シリアルリサイクルラーの処理とまったく同じであり、それでも単一のスレッドです。
3)並列圧縮コレクター:若い世代の処理は、平行コレクターのアルゴリズムとまったく同じアルゴリズムです。しかし、異なるアルゴリズムは古い世代に使用され、実際には異なる領域に分割され、ラベル付けと圧縮アルゴリズムがあります。
old昔をいくつかの固定領域に分割します。
markステージ(マルチスレッドパラレル)、マークリーチ可能なオブジェクト。
summary Summary stage(シリアル実行)。左から数値(オブジェクト密度が低い)に達する領域を見つけると、この領域とその右の領域が圧縮されて回復します。左端は密な領域④コンパクトステージ(マルチスレッドパラレル)で、ロードする必要がある領域を特定し、これらの領域に並行してデータをコピーします。このプロセスの後、古い世代の一方の端に多数のアクティブオブジェクトがあり、もう一方の端に大きなスペースがあります。
4)同時識別 - クリーニングとリサイクル(CMS):若い世代の処理は、並列リサイクルのアルゴリズムとまったく同じアルゴリズムです。しかし、異なるアルゴリズムは古い世代に使用されますが、マーククリーニングアルゴリズムはまだ使用されています。
①初期識別(プログラムの一時停止):直接参照されるオブジェクト(第1レベルオブジェクト)をマークします。
concurrent識別(プログラムの実行):第1レベルのオブジェクトを介して他の到達可能なオブジェクトを見つけます。
③Remark(プログラムの一時停止):マルチスレッドパラレル再マークオブジェクトは、並行性のために見逃された可能性のあるオブジェクト(単に話すだけで、それはミッシングです)
④同時クリーニング(プログラムが実行されます)
4。メモリ管理のヒント
1)直接的な数量を使用してみてください。
2)StringBuilderとStringBufferを使用して、文字列の連結およびその他の操作を実行します。
3)できるだけ早く役に立たないオブジェクトをリリースします。
4)静的変数をできるだけ使用しないようにしてください。
5)一般的に使用されるオブジェクトのキャッシュ:オープンソースのオープンソースキャッシュを使用して実装できます。例:oscache、ehcache;
6)finalize()メソッドを使用しないようにしてください。
7)必要に応じて、ソフト参照ソフトランスを使用することを検討できます。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。