10

有谁知道为什么 java 7 无法收集应用程序的永久代,导致 java.lang.OutOfMemoryError: PermGen,而 java 5 收集永久代并且应用程序运行良好?

应用程序在循环中评估 jython 表达式,一次迭代大约是。5 秒。循环体如下所示:

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

为在 java 7 和 java 5 中运行的应用程序拍摄的 jvisual vm 屏幕截图。

在这两种情况下,都使用相同的参数:

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

爪哇 7 爪哇 5

4

2 回答 2

2

有一个重现问题的小例子,我发现在 Eclipse 之外的 java 7 中运行的程序不会在永久代中出现内存泄漏。

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 中的调试应用程序没有这个问题。

于 2012-08-16T08:08:54.037 回答
0

permgen 泄漏的一种可能性是每个 PyInteger 实现的 Serializable 接口被存储在静态class_to_type映射 (PyType.java:101) 中,这是一个 Jython错误。我知道在 5 到 7 之间对 permgen 分配的唯一有趣的变化是删除了 7 中的实习生字符串以及对直接字节缓冲区内存分配的一些更改,因此您的图形的时间行为可能可以通过卸载来解释Java 5 中每次迭代的类型。

于 2012-08-15T13:49:24.993 回答