2012-04-25 4 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()); 
     } 
    } 

} 

Я запустить его, изменив значение N в if(depth < N). Вот результат;

когда глубина 1000

INIT = 16777216 (16384K) используется = 288808 (282K), совершенные = 16252928 (15872K) макс = 259522560 (253440K) Свободная память в запуске 15964120 свободной памяти в конце 15964120 init = 16777216 (16384K) used = 288808 (282K) совершил = 16252928 (15872K) max = 259522560 (253440K) Свободная память 15964120 init = 16777216 (16384K) used = 288808 (282K) commit = 16252928 (15872K) max = 259522560 (253440K)

, когда глубина 1500

INIT = 16777216 (16384K) используется = 288808 (282K), совершенные = 16252928 (15872K) макс = 259522560 (253440K) Свободная память в запуске 15964120 свободной памяти в конце 15964120 INIT = 16777216 (16384K) используется = 288808 (282K) совершено = 16252928 (15872K) max = 259522560 (253440K) Свободная память 15873528 init = 16777216 (16384K) used = 379400 (370K) commit = 16252928 (15872K) max = 259522560 (253440K)

, когда глубина составляет 6000

INIT = 16777216 (16384K) используется = 288808 (282K), совершенные = 16252928 (15872K) макс = 259522560 (253440K) Свободная память в запуске 15964120 свободной памяти в конце 15692784 INIT = 16777216 (16384K) используется = 560144 (547K) совершенные = 16252928 (15872K) макс = 259522560 (253440K) Free Memory 15692784 INIT = 16777216 (16384K) используется = 560144 (547K), совершенные = 16252928 (15872K) макс = 259522560 (253440K)

, когда глубина 6500 (Исключение в потоке «главный» java.lang.StackOverflowError)

init = 16777216 (16384K) used = 288808 (282K)) commit = 16252928 (15872K) max = 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

** ** Наблюдение, я обнаружил, что J начнут выпускать когда я создаю огромное количество объектов, например, 1-2 лакхов. Это означает, что это не утечка памяти, но 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 определенно не java, но я не понимаю, что вы делаете достаточно хорошо, чтобы редактировать его. 0_0 – Lucas

+0

Все, что я делаю, это использовать первый аргумент программы, чтобы выяснить, сколько объектов сделать, и делая это в цикле. –

+0

+1 для 2-го праграфа и программы. Однако я сталкиваюсь с той же проблемой (исключая часть исключения), когда я изменяю программу на вашем пути. –

0

Это не свидетельствует о утечке памяти. Программа бросает StackOverflowError не OutOfMemoryError.Фактически, это происходит потому, что конструктор вызывает себя рекурсивно, а когда количество рекурсивных вызовов превышает некоторое большое количество (от 6 000 до 6500), у вас заканчивается стек.

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

Нет. Метод finalize(), скорее всего, не вызывается, поскольку GC не запускается. И это не сработало, потому что вы не заполнили кучу. И даже если это не настоящее объяснение, нет никакой гарантии, что метод 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.

Это потому, что вы не поймать исключение поскольку StackOverflowError наследуется от Error, который не является частью ветви наследования Exception, а скорее брат Exception, во всяком случае у вас нет кода в улове, последний два метода вашей попытки не выполняются, поскольку исключение было выбрано.

В заключение вы не обнаружили утечки памяти, утечки памяти происходят в java, когда у вас есть ссылки на объекты, которые доступны (прямо или косвенно) из потока выполнения в какой-то момент, например, вы храните объекты в коллекции что вы можете достичь, или одиночные игры.

Сам сборщик мусора достаточно умен, чтобы освобождать графы объектов, которые вообще недоступны из программы.

Надеюсь, что смогу прояснить ситуацию. не

+0

его сбивает с толку: «В любом случае у вас нет кода в catch, последние два метода вашей попытки не выполняются, потому что исключение было выбрано». Я сказал, что последние 2 заявления выполнены. –

+0

Кроме того, я попытался вызвать gc() вручную. Тем не менее, он не вызывает finalize(), а используемое пространство находится в конце программы. –

1

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

Нет нет утечки памяти вы всегда держать доступную ссылку на ваш testObj объект и это причина, почему finalize никогда не будет вызываться в приложении.

Все, что вы делаете в своем приложении, - это создать огромный граф объектов.

Here вы можете найти объяснение, как создать настоящую утечку памяти в java.

+0

'testObj' имеет живую ссылку. Но что насчет первого экземпляра 'N-1', присвоенного' mobj'? На них не ссылаются никакие объекты. –

1

Уже большинство ответов объясняет разницу между утечкой StackOverflowError и утечкой памяти.

  • Нет свободной памяти до N = 1000. Но когда N = 1500, в конце программы есть 2 разных значения для используемой памяти, то есть 282K и 370K. Почему это так?

  • Это связано с тем, что каждый раз, когда вы создаете новый объект и предыдущий объект, становятся недоступными (ссылки отсутствуют, переопределение ссылки) и, следовательно, могут быть освобождены, если требуется.

До сих пор простейший пример, чтобы заставить 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.util.Arrays.copyOf (Arrays.java:2882) в java.lang.AbstractStringBuilder.expandCapacity (AbstractStringBuilder.java:100) в java.lang.AbstractStringBuilder.append (AbstractStringBuilder.java:390) на java.lang.StringBuilder.append (StringBuilder.java:119) на com.cctest.algotest.st ring.PrintSeries.convert (PrintSeries.java:17) на com.cctest.algotest.string.PrintSeries.main (PrintSeries.java:10)