目前,我们正在研究此问题。我们创建了一个样本程序来重现此行为:
import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class X
{
private static final String XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><x test=\"test\" />";
@XmlAttribute
String test;
public static void main( String[] args ) throws JAXBException, InterruptedException
{
System.out.println("start");
while ( true )
{
JAXBContext jc = JAXBContext.newInstance( X.class );
Unmarshaller unmarshaller = jc.createUnmarshaller();
X object = (X) unmarshaller.unmarshal( new ByteArrayInputStream( XML.getBytes() ) );
System.out.println( object.test );
}
}
}
JDK7可以保持PermGenSpace的清洁。(使用16M PermGen模拟) JDK7运行内存
使用JDK8,应用程序运行缓慢并出现OOM异常。 VisualVM捕获异常并在可用的Metaspace的最大值上保持进程运行。即使在这里也会在运行一段时间后陷入困境。 (使用16M Metaspace模拟) JDK8运行内存
有人有想法如何获得垃圾收集器的传统行为,以便我们不会遇到这些内存不足的问题吗?或者您有任何其他处理此问题的想法吗?
谢谢。
编辑1: JDK7运行参数:
-XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:PermSize=1M -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError
=> 不创建堆转储文件
JDK8运行参数:
-XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:MaxMetaspaceSize=16M -XX:MetaspaceSize=1M -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError
=> 运行时生成堆转储文件。
VisualVM的可用内存不显示真正的最大metaspace值。如果不受限制,则metaspace会不断增加,直到超出内存为止。
编辑2:
我尝试了JDK8中所有可用的垃圾收集器。它们都有同样的问题。
编辑3:
在我们的实际应用程序中,通过交换库来解决问题非常困难,因为JAXB与我们应用程序的几个模块之间的耦合很重。因此,短期内需要修复垃圾收集器行为。长期的正确修复已经计划好了。