#このチュートリアルの動作環境: Windows7 システム、Java8 バージョン、DELL G3 コンピューター。メモリ リークとは、プログラムがメモリを申請した後、割り当てられたメモリ領域を解放できないことを意味します。メモリ オーバーフローとは、プログラムがメモリを申請したときに、申請者が使用できる十分なメモリがないこと、または int データを保存するためのストレージ スペースが提供されているにもかかわらず、長いデータが保存され、その結果メモリが不足していることを意味します。 OOM エラーが報告されます。メモリ リークが蓄積すると、最終的にはメモリ オーバーフローが発生します。
最初のステップは、JVM 起動パラメータを変更し、メモリを直接増やすことです。 (-Xms および -Xmx パラメーターを必ず追加してください。)
2 番目のステップは、エラー ログをチェックして、「OutOfMemory」エラーの前に他の例外またはエラーがあるかどうかを確認することです。
3 番目のステップは、コードを詳しく調べて分析し、メモリ オーバーフローが発生する可能性のある場所を特定することです。
次の点に注目してください:
データベース クエリにすべてのデータを取得するクエリがあるかどうかを確認します。一般に、10 万件のレコードが一度にメモリにフェッチされると、メモリ オーバーフローが発生する可能性があります。この問題は比較的隠されています。オンラインになる前はデータベース内のデータが少なく、問題が発生する可能性は低かったのですが、オンラインになった後はデータベース内のデータが増え、1 つのクエリでメモリ オーバーフローが発生する可能性があります。したがって、データベース クエリにはページングを使用するようにしてください。
コード内に無限ループや再帰呼び出しがないか確認してください。
新しいオブジェクト エンティティを繰り返し生成する大規模なループが存在するかどうかを確認します。
データベースクエリに全データを一度に取得するクエリがあるか確認してください。一般に、10 万件のレコードが一度にメモリにフェッチされると、メモリ オーバーフローが発生する可能性があります。この問題は比較的隠されています。オンラインになる前はデータベース内のデータが少なく、問題が発生する可能性は低かったのですが、オンラインになった後はデータベース内のデータが増え、1 つのクエリでメモリ オーバーフローが発生する可能性があります。したがって、データベース クエリにはページングを使用するようにしてください。
List や MAP などのコレクション オブジェクトが使用後に消去されていないか確認してください。 List や MAP などのコレクション オブジェクトには常にオブジェクトへの参照があるため、これらのオブジェクトは GC によってリサイクルできません。
メモリ オーバーフローの 10 のシナリオ
JVM の実行時には、まずクラス ローダー (classLoader) を使用して、次のバイトコード ファイルをロードする必要があります。必要なクラス。ロード後、実行のために実行エンジンに渡されますが、実行プロセス中には、データを保存するための一定期間のスペースが必要になります (CPU やメイン メモリに似ています)。このメモリ空間の割り当てと解放のプロセスは、注意が必要なランタイム データ領域です。メモリ オーバーフローは、クラス ローダーのロード中に発生します。メモリ オーバーフローは、OutOfMemoryError と StackOverflowError の 2 つのカテゴリに分類されます。以下に 10 個のメモリ オーバーフローの状況をリストし、サンプル コードを通じてメモリ オーバーフローがどのように発生するかを説明します。1.java ヒープ メモリ オーバーフロー
java.lang.OutOfMemoryError:Java ヒープ スペース例外が発生すると、ヒープ メモリがオーバーフローします。1)、問題の説明
## がトリガーされます。
##2)、サンプル コード上記例 リクエストのみの場合 1回5mのメモリを確保した場合、リクエスト量は少なくガベージコレクションは正常に行われエラーは発生しませんが、一度同時実行が発生するとメモリの最大値を超えてメモリオーバーフローが発生します投げられるだろう。
3. 解決策まず、コードに問題がない場合は、2 つの jvm パラメーター -Xms と -Xmx を適切に調整し、ストレス テストを使用してこれらを調整します。最適値を達成するための 2 つのパラメータ。 2 番目に、ファイルのアップロードやデータベースからの大きなバッチの取得など、大きなオブジェクトのアプリケーションを避けるようにしてください。これは避ける必要があります。チャンクまたはバッチで処理するようにしてください。これは、通常の安定した処理に役立ちます。システムの実行。 最後に、リクエストの実行速度を上げてみます。ガベージ コレクションは早ければ早いほど良いです。そうしないと、大量の同時実行が発生したときに、新しいリクエストがメモリを割り当てることができなくなり、システムの雪崩を容易に引き起こします。 2、Java ヒープ メモリ リーク1)、問題の説明
Java のメモリ リークは、次のようなオブジェクトです。 not アプリケーションによって再度使用されますが、ガベージ コレクションによって認識されません。したがって、これらの未使用のオブジェクトは Java ヒープ領域に無期限に存在し続けます。一定の蓄積により、最終的には java.lang.OutOfMemoryError がトリガーされます。 2)、サンプル コード上記のコードを実行すると、純粋なキャッシュ ソリューションが基になるスケールを 10,000 にマッピングするだけであると仮定すると、問題なく永久に実行されることが期待されるかもしれません。 HashMap にすでに存在するすべてのキーの代わりに要素を追加します。ただし、キー クラスはそのquals() メソッドをオーバーライドしないため、実際には要素は追加され続けます。
漏洩したコードは継続的に使用されるため、時間の経過とともに「キャッシュされた」結果が大量の Java ヒープ領域を消費することになります。リークしたメモリがヒープ領域内のすべての使用可能なメモリを埋めると、ガベージ コレクションでクリーンアップできなくなり、java.lang.OutOfMemoryError が発生します。
3)、解決策対応する解決策は比較的単純で、equals メソッドを書き直すだけです:
3. ガベージ コレクション タイムアウトのメモリ オーバーフロー
1)、問題の説明: アプリケーションが使用可能なメモリをすべて使い果たし、GC オーバーヘッド制限がエラーを超え、GC がエラーのクリアに複数回失敗すると、java.lang がトリガーされます。 JVM が GC の実行に多くの時間を費やしても効果はほとんどなく、GC プロセス全体が制限を超えると、エラーがトリガーされます (デフォルトの JVM 構成の GC 時間は 98% を超え、リサイクルされたヒープ メモリは 2 未満です) %)。
2)、サンプル コード
3)、解決策
オブジェクトのライフサイクルを短縮するには、ガベージ コレクションを迅速に実行してみてください。
4. メタスペース メモリ オーバーフロー
1)、問題の説明
メタスペースがオーバーフローすると、システムは Java をスローします。 .lang.OutOfMemoryError: メタスペース。この異常な問題の原因は、システムに大量のコードがあるか、多くのサードパーティ パッケージを参照しているか、動的コード生成とクラス ロードが使用されており、その結果、メタスペース内で大きなメモリ フットプリントが発生することです。
2)、サンプル コード
3)、解決策
デフォルトでは、メタスペースのサイズはローカル メモリによってのみ制限されます。ただし、マシン全体のパフォーマンスの観点から、この項目はマシン全体のサービスダウンを引き起こさないようにできる限り設定する必要があります。
他の JVM プロセスに影響を与えないようにパラメーター構成を最適化します
-XX:MetaspaceSize、初期スペース サイズ、この値が指定された場合にガベージ コレクションがトリガーされますタイプのアンロードを実行すると、GC が値を調整します。大量のスペースが解放されると、値は適切に下げられます。解放されるスペースが少量の場合は、値を超えない限り、値は適切に増加します。 MaxMetaspaceSize。
-XX:MaxMetaspaceSize、最大スペース。デフォルトでは制限はありません。
上記の 2 つのサイズ指定オプションに加えて、2 つの GC 関連属性があります: -XX:MinMetaspaceFreeRatio. GC 後、メタスペースの最小残りスペース容量の割合が、割り当てられたスペースまで減ります。コレクション。 -XX:MaxMetaspaceFreeRatio、GC 後、メタスペースの最大残りスペース容量のパーセンテージが、スペースの解放によって発生するガベージ コレクションに減らされます。
サードパーティ パッケージを慎重に参照してください
サードパーティ パッケージについては、慎重に選択し、不要なパッケージを削除してください。これは、コンパイルとパッケージ化の速度を向上させるだけでなく、リモート展開の速度も向上します。
クラスを動的に生成するフレームワークに重点を置く
動的に生成されるクラスを多数使用するフレームワークについては、ストレス テストを行って検証する必要があります。動的に生成されたクラス メモリ要件を超えると、例外がスローされます。
5. ダイレクトメモリオーバーフロー
1) 問題の説明
ByteBuffer で assignDirect() を使用する場合に使用されます。多くの javaNIO (netty など) フレームワークは他のメソッドとしてカプセル化されており、この問題が発生すると、java.lang.OutOfMemoryError: ダイレクト バッファ メモリ例外がスローされます。
ByteBuffer の assignDirect メソッドをクリアせずに直接または間接的に使用すると、同様の問題が発生します。
2)、サンプル コード
3)、解決策
同様の操作を頻繁に行う場合は、パラメーターの設定を検討してください: -XX: MaxDirectMemorySize を設定し、時間内にメモリをクリアします。
6. スタック メモリ オーバーフロー
1)、問題の説明
スレッドが Java メソッドを実行すると、JVM新しいスタック フレームが作成され、スタックの先頭にプッシュされます。このとき、新しいスタック フレームが現在のスタック フレームとなり、メソッドの実行時にパラメータ、ローカル変数、中間命令などのデータを格納するためにスタック フレームが使用されます。
メソッドがそれ自体を再帰的に呼び出すと、新しいメソッドによって生成されたデータ (新しいスタック フレームとしても理解できます) がスタックの先頭にプッシュされます。メソッドがそれ自体を呼び出すたびに、現在のメソッドのデータがスタックにプッシュされます。したがって、再帰の各レベルでは、新しいスタック フレームを作成する必要があります。その結果、スタック内のメモリが再帰呼び出しによって消費され、再帰呼び出しが 100 万回行われると、100 万個のスタック フレームが生成されます。これにより、スタック メモリのオーバーフローが発生します。
2)、サンプル コード
3)、解決策
実際にプログラム内に再帰呼び出しがあり、スタック オーバーフローが発生した場合は、次の値を増やすことができます。 -Xss サイズにより、スタック メモリのオーバーフローの問題を解決できます。再帰呼び出しにより無限ループの形成が防止されます。そうしないと、スタック メモリのオーバーフローが発生します。
7. ローカルスレッド作成時のメモリオーバーフロー
1) 問題の説明
スレッドは基本的にローカルスレッド以外のメモリ領域のみを占有します。このエラーは、ヒープ以外のメモリ領域をスレッドに割り当てることができないことを示します。これは、メモリ自体が十分ではないか、ヒープ領域が大きく設定されすぎてメモリがあまり残っていないためです。 、そしてスレッドのせいでメモリ自体を消費するので十分ではありません。
2)、サンプル コード
3)、解決策
最初に、オペレーティング システムにスレッド数の制限があるかどうかを確認します。 、シェルを使用する スレッドも作成できません。これが問題である場合は、システムがサポートできるファイルの最大数を調整する必要があります。
日々の開発では、スレッドの最大数が制御可能であることを確認し、スレッド プールを恣意的に使用しないようにしてください。際限なく成長することはできません。
8. スワップ領域を超えたメモリ オーバーフロー
1) 問題の説明
Java アプリケーションの起動プロセス中, 必要なメモリは、-Xmx およびその他の同様の起動パラメータによって制限できます。 JVM によって要求された合計メモリが利用可能な物理メモリよりも大きい場合、オペレーティング システムはメモリからハード ディスクへのコンテンツの変換を開始します。
一般に、JVM はスワップ領域不足エラーをスローします。これは、アプリケーションが JVM ネイティブ ヒープにメモリを割り当てるように要求できず、ネイティブ ヒープが枯渇しそうになった場合に、エラー メッセージに次の内容が含まれることを意味します。割り当て失敗のサイズ (ワードセクション) とリクエスト失敗の理由。
2)、解決策
システムのスワップ領域のサイズを増やします。個人的には、スワップ領域を使用するとパフォーマンスが大幅に低下すると思います。この方法は推奨されません。最大メモリはシステムの物理メモリを超えます。次に、システム スワップ領域を削除し、アプリケーションのパフォーマンスを確保するためにシステム メモリのみを使用します。
9. 配列オーバーフロー メモリ オーバーフロー
1) 問題の説明 この種のメモリ オーバーフローの説明が発生することがあります 要求された配列サイズが VM の制限を超えています一般に、Java には、アプリケーションが割り当てることができる配列の最大サイズに制限があります。この制限はプラットフォームによって異なりますが、通常は 10 ~ 21 億要素です。 「要求された配列サイズが VM 制限を超えています」エラーが発生する場合、アプリケーションが Java 仮想マシンがサポートできるよりも大きい配列を割り当てようとしていることを意味します。 JVM は配列にメモリを割り当てる前に、割り当てられたデータ構造がこのプラットフォームでアドレス指定可能かどうかというプラットフォーム固有のチェックを実行します。
2)、サンプルコード
以下は配列が上限を超えているコードです。
3)、解決策
したがって、配列の長さはプラットフォームで許可されている長さの範囲内である必要があります。ただし、主に Java 配列のインデックスが int 型であるため、このエラーが発生することは一般にまれです。 Java の最大の正の整数は 2^31 - 1 = 2,147,483,647 です。また、プラットフォーム固有の制限はこの数値に非常に近い可能性があります。たとえば、私の環境 (64 ビット macOS、Jdk1.8 を実行) では、最大 2,147,483,645 (Integer.MAX_VALUE-2) の長さの配列を初期化できます。配列の長さが 1 増加して nteger.MAX_VALUE-1 に達すると、OutOfMemoryError が発生します。
10. システムがプロセス メモリ オーバーフローを強制終了します
1). 問題の概要. 問題を説明する前に、まず、オペレーティング システム: オペレーティング システムはプロセスの概念に基づいて構築されています。これらのプロセスはカーネル内で動作します。「メモリ不足キラー」と呼ばれる非常に特殊なプロセスがあります。システムのメモリが不十分であることをカーネルが検出すると、OOM キラーがアクティブになり、現在最も多くのメモリを占有しているのが誰かを確認して、プロセスを強制終了します。
通常、「メモリ不足: プロセスを強制終了するか子を犠牲にする」エラーは、使用可能な仮想仮想メモリ (スワップ領域を含む) がオペレーティング システム全体が危険にさらされるまで消費されるとトリガーされます。この場合、OOM Killer は「不正プロセス」を選択して強制終了します。
2)、サンプル コード
3)、解決策
スワップ領域を追加すると Java ヒープ領域例外を軽減できますが、それでも最善の解決策は、Java アプリケーションで十分なメモリを使用できるようにシステム メモリをアップグレードし、この問題が発生しないようにすることをお勧めします。
まとめ: 上記の 10 種類のメモリ オーバーフローの状況を通じて、誰もが実際に問題に遭遇したときの解決方法を理解できるようになります。また、実際のコーディングでは次のことも覚えておく必要があります。
#サードパーティの jar パッケージは慎重に導入する必要があり、コンパイル速度とシステム メモリの使用率を向上させるために、不要な jar パッケージは断固として削除する必要があります。再帰呼び出しの場合、再帰のレベルも制御する必要があります。高すぎたりスタックの深さを超えたりしないようにする必要があります。
スタックに割り当てられるメモリは大きければ大きいほど良いわけではありません。スタック メモリが大きければ大きいほど、スレッドの数が多くなり、ヒープ用のスペースがあまり残らなくなるためです。そして OOM を投げるのは簡単です。通常、JVM のデフォルトパラメータ (再帰を含む) には問題はありません。
推奨される関連ビデオ チュートリアル: Java ビデオ チュートリアル
以上がJavaのメモリリークとメモリオーバーフローとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。