Java 7 не может собрать постоянное поколение, которое собирается java 5

Кто-нибудь знает, почему java 7 не может собрать постоянное поколение приложения, в результате чего java.lang.OutOfMemoryError: PermGen, а java 5 собирает постоянное поколение, а приложение работает хорошо?

Приложение выполняет оценку выражений jython в цикле, одна итерация - ок. 5 сек. Тело цикла выглядит так:

PythonInterpreter py = new PythonInterpreter();
py.set("AI", 1);
((PyInteger)py.eval(expr)).getValue()

Скриншоты jvisual vm для приложения, запущенного в java 7 и java 5.

В обоих случаях используются одни и те же параметры:

-Xmx700m 
-XX:MaxPermSize=100m
-XX:+HeapDumpOnOutOfMemoryError
-Xloggc:"C:\Temp\gc.log" -XX:+PrintGCDetails  -XX:-TraceClassUnloading -XX:+PrintClassHistogram 

java 7java 5

Ответ 1

Имея небольшой пример для воспроизведения проблемы, я обнаружил, что программа, запущенная в java 7 вне Eclipse, не страдает утечкой памяти в постоянном поколении.

import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

public class Test01 {

  public static void main(String[] args) throws Exception  {
    PySystemState.initialize();
    long startNanos = System.nanoTime();
    for(int i = 0; i < 450000; i++)    {
        PythonInterpreter pi = new PythonInterpreter();
        long elapsedNanos = System.nanoTime() - startNanos;
        int avgStepInMicros = (int)((elapsedNanos / 1000) / (i+1));
        final String code = String.format(
                "stepNo = %d + 1\n" +
                "if stepNo %% 100 == 0:\n" + 
                "  print 'stepNo: %%d,  elapsedMillis: %%d, avgStepInMicros: %%d' %% (stepNo, %d, %d)", i, elapsedNanos/1000000, avgStepInMicros);
        pi.exec(code);
    }
  }
}

MAT показал поток отладчика как корень сборщика мусора.

GCRoot

Странно то, что отладка приложения в java 5 не имеет этой проблемы.

Ответ 2

Одной из возможностей для утечки пергентов является интерфейс Serializable, реализованный каждым PyInteger, хранящимся в статической карте class_to_type (PyType.java:101), это Jython bug. Единственные интересные изменения в распределении перменства между 5 и 7, о которых я знаю, это удаление внутренних строк в 7 и некоторые изменения в распределении памяти прямого байтового буфера, поэтому вместо этого временное поведение вашего графика может быть объяснено с помощью разгрузка типов на каждой итерации в Java 5.