2012-04-25 10 views
2

私は、Javaでサンプルプログラムデモのメモリリークを構築します。メモリリークですか?

public class MemoryLeakTest { 
    static int depth = 0; 
    int number=0; 
    MemoryLeakTest mobj; 

    MemoryLeakTest(){ 
     number = depth; 
     if(depth < 6500){ 
      depth++; 
      mobj = new MemoryLeakTest(); 
     } 
    } 

    protected void finalize(){ 
     System.out.println(number + " released."); 
    } 

    public static void main(String[] args) { 
     try{ 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
      System.out.println("Free Memory in starting "+ Runtime.getRuntime().freeMemory()); 
      MemoryLeakTest testObj = new MemoryLeakTest(); 
      System.out.println("Free Memory in end "+ Runtime.getRuntime().freeMemory()); 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
     } 
     catch(Exception exp){} 
     finally{ 
      System.out.println("Free Memory"+ Runtime.getRuntime().freeMemory()); 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
     } 
    } 

} 

if(depth < N)のNの値を変更して実行します。ここに結果があります。

深さが1000

エンド15964120に15964120 空きメモリを起動中= 16252928(15872K)MAX = 259522560(253440K) 無料コミットメモリのinit = 16777216(16384K)を使用= 288808

(282K)であります 初期= 16777216(16384K)使用= 288808(282K)コミット= 16252928(15872K)最大= 259522560(253440K) 空きメモリ15964120 init = 16777216(16384K)= 288808(282K)コミット= 16252928(15872K)max = 259522560(253440K)

深さは1500

のinit = 16777216(16384K)のinit = 16777216エンド15964120 に15964120 空きメモリを起動中= 16252928(15872K)MAX = 259522560(253440K) 空きメモリを犯し= 288808(282K)が使用されています(16384K)使用= 379400(370K)コミット= 16252928(15872K)最大= 259522560(253440K)使用済み= 288808(282K)コミット済み= 16252928(15872K)最大= 259522560(253440K) 空きメモリ15873528 初期= 16777216

深さが6000の場合

使用

のinit = 16777216(16384K)= 288808最後に15964120 空きメモリを開始するに= 16252928(15872K)MAX = 259522560(253440K) 無料コミットメモリ(282K)15692784 のinit = 16777216使用(16384K)= 560144(547K深さがあるとき)= 16252928(15872K)MAX = 259522560(253440K) 空きメモリー15692784 のinit = 16777216(16384K)を使用= 560144(547K)コミット= 16252928(15872K)MAX = 259522560(253440K)

を犯し6500(スレッド "main"の例外java.lang.StackOverflowError)

init = 16777216(16384K)used = 288808(282K )コミット= 16252928(15872K)最大= 259522560(253440K) 空きメモリの開始15964120 空きメモリの最後15676656 init = 16777216(16384K)= 576272(562K)コミット= 16252928(15872K)max = 259522560(253440K)

私の質問は次のとおりです。

  1. finalize()を呼び出していません。メモリリークですか?
  2. N = 1000までの空きメモリの変更はありません。しかし、N = 1500の場合、プログラムの最後に使用されたメモリの値が2つ(すなわち、282Kと370K)になります。 なぜそれはそうですか?
  3. N = 6500の場合、JVMはエラーを生成します。だからなぜ最後の2つが試行されますか? try {}のステートメントが実行されます。
+0

**観察**、私はJVMが放出し始めることがわかりました私は1-2 lakhsのようなオブジェクトの巨大な量を作成するときのメモリ。メモリリークではなく、GCが実際に必要なときにメモリを解放することを意味します。さらに、最初にオブジェクト9000を解放してから、8999、次に8998を解放するように、オブジェクトのトップをヒープ上に解放します。興味深い.. –

+0

観測2:GCを実行した後でも、より高い使用領域を与えるgetHeapMemoryUsage。 –

+0

http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java:Javaのメモリリークに本当に便利です! – Val

答えて

1

あなたのプログラムは、Javaが "抱擁"を世話するので、 "リーク"しません。それはガベージコレクション言語の利点です。

しかし、あなたが持っているのはStackOverFlowエラーです。基本的に、スタック(あなたが入っている機能のチェーンであり、どれくらいの深さであるか)はヒープよりずっと小さいです。ヒープはメインメモリのサイズの「多かれ少なかれ」です。各スレッドのスタックはずっと小さくなっています。基本的には、あなたの "深さ"のことを行うことによってその限界に達しています。

あなたは「漏洩」(またはあなたが最終的にいずれかを持っていないだろうという考え)をテストする場合より、このような何かしてみてください:

public class MemoryLeakTest { 
    int number=0; 
    public MemoryLeakTest mobj; 

    MemoryLeakTest(int num){ 
     number = num; 
    } 

    protected void finalize(){ 
     System.out.println(number + " released."); 
    } 

    public static void main(String[] args) { 
     try{ 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
      System.out.println("Free Memory in starting "+ Runtime.getRuntime().freeMemory()); 
      MemoryLeakTest first = new MemoryLeakTest(0); // Keep a reference to one of them 
      MemoryLeakTest current = first; 
      for(int i = 1; i < Int.Parse(args[0]); i++) // forgive me, Java's been a while. This may be C#. But parse the first arg for your number of objects 
      { 
       current.mobj = new MemoryLeakTest(i); 
       current = current.mobj; 
      } 
      System.out.println("Free Memory in end "+ Runtime.getRuntime().freeMemory()); 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
     } 
     catch(Exception exp){} 
     finally{ 
      System.out.println("Free Memory"+ Runtime.getRuntime().freeMemory()); 
      System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); 
     } 
    } 

} 

すべてであなたのオブジェクトの「連鎖」を与えますfirstが範囲外になるまでメモリ。

+0

あなたのforループはdefinitly javaではありませんが、私はあなたがそれを編集するのに十分うまくやっているのを得ていません0_0 – Lucas

+0

私がやっているのは、プログラムの最初の引数を使って、それをループで行います。 –

+0

+1第2プラグラフとプログラムの場合+1。しかし、私はあなたの方法でプログラムを修正するとき、同じ問題(例外部分を除く)に直面しています。 –

0

これはメモリリークの証拠ではありません。プログラムはStackOverflowErrorではなく、OutOfMemoryErrorです。実際には、コンストラクタ自体が再帰的に呼び出されており、再帰呼び出しの数が大きい(6,000から6,500まで)場合、スタックの領域が不足しています。

It is not calling finalize(). Is it memory leak?

いいえ、GCが実行されていないため、finalize()メソッドが呼び出されていない可能性があります。あなたがヒープを満たしていないので、それは実行されていません。実際の説明ではなくても、finalize()メソッドが呼び出されるという保証はありません。あなたが持っている唯一の絶対的な保証はfinalize()と呼ばれる前にのオブジェクトのメモリがJVMによって再利用されるということです。

There is not change in free memory up to N=1000. But when N=1500 there is 2 different values for used memory at the end of the program ie 282K and 370K. Why does it so?

私はそれがなぜ起こるのか分かりませんが、それは何も重要でないと思います。 (メモリの割り当てと使用パターンのようなものに非決定性の源となることができますJVMでボンネットの下に起こるあらゆる種類のものがあります。)

When N=6500, JVM generates error. So why last 2 statements of try{} are executed.

finally内のステートメントが常に実行され、しない限りJVMは突然終了します。 StackOverflowErrorがスローされると、他の例外と同様に伝搬し、キャッチして(場合によっては)回復することができます。ファイナライズが呼び出されることが保証されていない

1

It is not calling finalize(). Is it memory leak?

、ガベージコレクタは、指定されたオブジェクトを収集するときに呼び出されるが、オブジェクトは、実行が終了する前に収集することが保証されていません。

There is not change in free memory up to N=1000. But when N=1500 there is 2 different values >for used memory at the end of the program ie 282K and 370K. Why does it so?

ガベージコレクタの実行と実行される瞬間に依存すると思います。

When N=6500, JVM generates error. So why last 2 statements of try{} are executed.

これが最後、あなたは例外継承枝の一部ではなく、Exceptionの弟であるErrorからStackOverflowError継承しているので、例外をキャッチしていないので、とにかくあなたがキャッチには、コードを持っていないです例外がスローされたため、2つのtryメソッドが実行されていません。

要約すれば、メモリリークは発生しませんでした。ある時点で実行フローから(直接的または間接的に)到達可能なオブジェクトへの参照があると、Javaでメモリリークが発生します。あなたが到達できる、またはシングルトン。

ガベージコレクタ自体は、プログラムから到達できないオブジェクトグラフを解放するのに十分なほどスマートです。

私はそれを明確にすることができます。

+0

それは混乱している "とにかく、キャッチにコードがないため、例外が投げられたために試行の最後の2つのメソッドが実行されていません。"最後の2つのステートメントが実行されたと私は言った。 –

+0

さらに、私は手動でgc()を呼び出してみました。それでも、finalize()は呼び出されておらず、プログラムの最後に使用された空き領域が多いです。 –

1

It is not calling finalize(). Is it memory leak?

んが、あなたが常にあなたのtestObjオブジェクト へのアクセスの参照を保持し、それがfinalizeアプリケーションで呼び出されることはありません理由です何のメモリリークはありません。

アプリケーションで行ったことは、巨大なオブジェクトグラフを作成することでした。

Here Javaで実際のメモリリークを作成する方法を説明しています。

+0

'testObj'にはライブ参照があります。しかし、 'mobj 'に割り当てられた最初の' N-1'インスタンスはどうでしょうか?彼らはどんなオブジェクトによっても参照されていません。 –

1

既に、StackOverflowErrorとメモリリークの違いはほとんどの回答で説明されています。

  • N = 1000までの空きメモリの変更はありません。しかし、N = 1500の場合、プログラムの最後に使用されたメモリには2つの異なる値、すなわち282Kと370Kがあります。なぜそれはそうですか?

  • これは、新しいオブジェクトを作成するたびに以前のobjが到達不能になり(参照がなく、参照が上書きされる)、必要に応じて解放できるためです。

これまでのところ、jvmにメモリ不足(リークなし)が発生するようにする最も単純な例です。スレッド内

public class PrintSeries { 

private static String COMMA = ","; 
private StringBuilder buildStream;// = new StringBuilder(); 

public static void main(String[] args) { 
    System.out.println(new PrintSeries().convert(10)); 
    System.out.println(new PrintSeries().convert(1000000000)); 
} 

private String convert(int n) { 
    buildStream = new StringBuilder(); 

    while (n > 1) { 
     buildStream.append(n-- + COMMA); 
    } 
    buildStream.append(n); 
    return buildStream.toString(); 
    } 
} 
  • 出力

    10,9,8,7,6,5,4,3,2,1 例外 "メイン" java.lang.OutOfMemoryErrorを:Javaヒープスペースjava.lang.AbstractStringBuilder.appendでjava.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) でjava.util.Arrays.copyOf(Arrays.java:2882) (AbstractStringBuilder.java:390) ででjava.lang.StringBuilder.append(StringBuilder.java:119) at com.cctest.algotest.st com.cctest.algotest.string.PrintSeries.mainでring.PrintSeries.convert(PrintSeries.java:17) (PrintSeries.java:10)

関連する問題