一些上下文:我们已将 Web 应用程序的环境从在 Java 7 上运行升级到在 Java 8 和 Tomcat 8 上运行(64 位架构,堆大小约 2 GB,永久代大小 = 256 MB,对元空间大小没有限制)。过了一会儿,我们开始收到以下错误:
java.lang.OutOfMemoryError:压缩的类空间
这意味着 UseCompressedClassPointers 所需的空间超过了 CompressedClassSpaceSize。那时,VisualVM 显示了 2 GB 的元空间大小。
现在使用 VisualVM 工具,我们可以看到元空间大小随着每个请求大约 3 MB 不断增加,但是堆似乎没有这样做。堆使用量呈锯齿形,每次 GC 后都会回到相同的低点。
我只能在使用 Java JAXB 操作时才知道应用程序正在泄漏元数据,但我无法用 VisualVM 证明这一点。
应用程序依赖 webservices-rt-1.4 作为 JAXB 实现提供者。应用程序使用编码、解码。 XSD 的类生成是使用 maven-jaxb2-plugin-0.13.1 完成的。
更新:
在跟踪类加载和卸载后,我发现 WebAppClassLoader 多次将相同的 JAXB 类加载到内存中,但从未清理过。此外,堆中没有它们的实例。我调试了,我看到JDK正在调用该方法
javax.xml.bind.JAXBContext com.sun.xml.bind.v2.ContextFactory.createContext 通过反射,这就是创建类的时间。
我虽然这些类是由 GC 清理的。清理是 classLoader 的责任吗?
问题:有没有办法分析元空间对象?为什么我在元空间中有泄漏但在堆中没有泄漏?他们没有关系吗?这甚至可能吗?
为什么应用程序可以与 PermGen 一起正常工作,但不能与 Metaspace 一起工作?
最佳答案
我面临类似的问题。
就我而言,内存泄漏是由 JAXBContext.newInstance(...)
引起的调用。
解决方案:
-Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true
VM 参数,如答案 Old JaxB and JDK8 Metaspace OutOfMemory Issue 关于memory-leaks - 如何分析 Java 8 压缩类空间中的内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40346869/