旧的JaxB和JDK8 Metaspace OutOfMemory问题

我们正在开发自10年以来开发的业务应用程序(100万+ LOC)。 在切换到JDK8时,我们遇到了JDK8的元空间问题。 这似乎与com.sun.xml.ws:webservices-rt:1.4(Metro 1.4)中引用的JaxB-Version有关。 由于应用程序中的密切链接以及通过JaxB创建类/实例的传统,因此在旧库中快速切换并不简单。

目前我们正在研究这个问题。 我们创建了一个重现此行为的示例程序:

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 = ""; @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,应用程序运行缓慢到OOMexception。 VisualVM捕获exception并使进程在最大可用Metaspace上运行。 即使在这里,它在最长时间运行了很长一段时间后才会被卡住。 (使用16M Metaspace模拟) 使用JDK8运行的内存

有没有人有一些想法如何获得垃圾收集器的遗留行为,所以我们不会遇到那些内存不足的问题? 或者您对如何处理此问题有任何其他想法?

谢谢。

edit1: 运行参数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的可用内存未显示实际的最大元空间值。 如果不受限制,则元空间不断增加,直到超过内存。

编辑2:

我已经为JDK8尝试了所有可用的垃圾收集器。 他们都有同样的问题。

编辑3:

由于JAXB与我们应用程序的几个模块之间存在大量耦合,因此在我们的实际应用中通过交换库进行解决是很困难的。 因此,短期内需要修复垃圾收集器行为。 从长远来看,已经计划好了。

我们解决了当前的问题,直到使用以下VM参数来解决应用程序中的所有问题:

 -Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true 

我希望这能帮助其他类似问题……

JAXBContext.newInstance()应该只使用一次来为您的类创建一个解组的上下文。 否则它会耗尽你的permgen或metaspace。