ホームページ  >  記事  >  Java  >  Java における典型的なメモリ リークの問題と解決策

Java における典型的なメモリ リークの問題と解決策

高洛峰
高洛峰オリジナル
2017-01-16 16:07:311505ブラウズ

Q: Java でメモリ リークはどのようにして発生しますか?
A: Java では、メモリ リークの原因は数多くあります。典型的な例は、hasCode メソッドと
equals メソッドを実装せず、HashMap に保存される Key クラスです。最終的には、多数の重複オブジェクトが生成されます。すべてのメモリ リーク
は、最終的に OutOfMemoryError 例外をスローします。 以下は、無限ループによるメモリ リーク
をシミュレートする簡単な例です。

import java.util.HashMap;
import java.util.Map;

public class MemoryLeak {

 public static void main(String[] args) {
  Map<Key, String> map = new HashMap<Key, String>(1000);

  int counter = 0;
  while (true) {
       // creates duplicate objects due to bad Key class
   map.put(new Key("dummyKey"), "value");
   counter++;
   if (counter % 1000 == 0) {
    System.out.println("map size: " + map.size());
    System.out.println("Free memory after count " + counter
      + " is " + getFreeMemory() + "MB");

    sleep(1000);
   }

    
  }
 }

 // inner class key without hashcode() or equals() -- bad implementation
 static class Key {
  private String key;

  public Key(String key) {
   this.key = key;
  }

 }

 //delay for a given period in milli seconds
 public static void sleep(long sleepFor) {
  try {
   Thread.sleep(sleepFor);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

 //get available memory in MB
 public static long getFreeMemory() {
  return Runtime.getRuntime().freeMemory() / (1024 * 1024);
 }

}

結果は次のとおりです:

map size: 1000
Free memory after count 1000 is 4MB
map size: 2000
Free memory after count 2000 is 4MB
map size: 1396000
Free memory after count 1396000 is 2MB
map size: 1397000
Free memory after count 1397000 is 2MB
map size: 1398000
Free memory after count 1398000 is 2MB
map size: 1399000
Free memory after count 1399000 is 1MB
map size: 1400000
Free memory after count 1400000 is 1MB
map size: 1401000
Free memory after count 1401000 is 1MB
.....
.....
map size: 1452000
Free memory after count 1452000 is 0MB
map size: 1453000
Free memory after count 1453000 is 0MB
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.util.HashMap.addEntry(HashMap.java:753)
 at java.util.HashMap.put(HashMap.java:385)
 at MemoryLeak.main(MemoryLeak.java:10)

Q: 上記のメモリ リークを解決するにはどうすればよいですか?
A: Key クラスの equals メソッドと hasCode メソッドを実装します。

    .....
static class Key {
 private String key;

 public Key(String key) {
  this.key = key;
 }

 
 @Override
 public boolean equals(Object obj) {

  if (obj instanceof Key)
   return key.equals(((Key) obj).key);
  else
   return false;

 }

 @Override
 public int hashCode() {
  return key.hashCode();
 }
}
.....

プログラムを再実行すると、次の結果が得られます:

 map size: 1
Free memory after count 1000 is 4MB
map size: 1
Free memory after count 2000 is 4MB
map size: 1
Free memory after count 3000 is 4MB
map size: 1
Free memory after count 4000 is 4MB
...
Free memory after count 73000 is 4MB
map size: 1
Free memory after count 74000 is 4MB
map size: 1
Free memory after count 75000 is 4MB

Q: 実際のシナリオでは、メモリ リークをどのように見つけますか?
A: 次のコードでスレッド ID を取得します

C:\>jps
5808 Jps
4568 MemoryLeak
3860 Main

コマンドラインで jconsole を開きます

C:\>jconsole 4568

hasCode と等しいを実装する Key クラスと実装なしのチャートは次のとおりです:

メモリ リークなし:

Java における典型的なメモリ リークの問題と解決策

原因のメモリ リーク:

Java における典型的なメモリ リークの問題と解決策

Java でのより一般的なメモリ リークの問題と解決策については、PHP 中国語 Web サイトに注意してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。