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 7]()
![java 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.