java - 从 Java 6 升级到 Java 7 时 native 堆上出现 OutOfMemoryError

标签 java jaxb garbage-collection jvm jboss5.x

我们最近将我们的大型网络应用程序(在 jboss 5 上运行)从 java 6 升级到 java 7。

几小时内,我们看到了 OutOfMemory 错误,看起来是 native 堆用完了。

我们运行的是 32 位 JVM,因此限制为 4GB,而 JVM 分配了 2GB。

在 Java 6 下,整个进程占用了大约 2.3GB,但在 Java 7 中,这个数量大大增加了,我们达到了 4GB 的限制,但没有触发完整的 GC,因为 Java 堆仍未满。

堆栈跟踪显示 XML 解码代码在每个请求上创建新的 SAXParserFactory,用于解压缩 jar 文件的 Inflater 类将大量数据存储在 native 堆中(约 200,000 个 Inflater 实例)。这让我觉得效率很低——新的 SAXParserFactory 和多个 Inflators。也许这是一个转移注意力的问题,但我没有它的 Java 6 版本来比较行为。

通过每隔几个小时手动运行一次 gc,应用程序可以愉快地运行几天,没有任何问题。但这不是解决方案。

问题是为什么内存分配增加了惊人的 1.5GB,我该如何阻止这种情况发生?

我希望更新的 Java 版本更高效、更快等等。但实际上我们在 JVM 中发现了内存泄漏问题。

无论如何堆栈跟踪如下:

# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 512128 bytes for Chunk::new
# An error report file with more information is saved as:
# /opt/SP/apps/er_core/current/hs_err_pid25455.log
00:49:30,072 ERROR [[DecouplingProcessServlet]] Servlet.service() for servlet DecouplingProcessServlet threw exception
java.lang.OutOfMemoryError
    at java.util.zip.Inflater.init(Native Method)
    at java.util.zip.Inflater.<init>(Inflater.java:101)
    at java.util.zip.ZipFile.getInflater(ZipFile.java:450)
    at java.util.zip.ZipFile.getInputStream(ZipFile.java:369)
    at org.jboss.virtual.plugins.context.zip.ZipFileWrapper.openStream(ZipFileWrapper.java:214)
    at org.jboss.virtual.plugins.context.zip.ZipEntryContext.openStream(ZipEntryContext.java:1066)
    at org.jboss.virtual.plugins.context.zip.ZipEntryHandler.openStream(ZipEntryHandler.java:153)
    at org.jboss.virtual.VirtualFile.openStream(VirtualFile.java:230)
    at org.jboss.virtual.plugins.vfs.VirtualFileURLConnection.getInputStream(VirtualFileURLConnection.java:93)
    at java.net.URLClassLoader.getResourceAsStream(URLClassLoader.java:233)
    at javax.xml.parsers.SecuritySupport$4.run(SecuritySupport.java:94)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.xml.parsers.SecuritySupport.getResourceAsStream(SecuritySupport.java:87)
    at javax.xml.parsers.FactoryFinder.findJarServiceProvider(FactoryFinder.java:283)
    at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:255)
    at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:126)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.getXMLReader(AbstractUnmarshallerImpl.java:100)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)
    at com.mycompany.global.er.decoupling.util.xml.JAXBHelper.bind(JAXBHelper.java:88)
    at com.mycompany.global.er.decoupling.util.xml.JAXBHelper.bind(JAXBHelper.java:56)
    at com.mycompany.global.er.decoupling.DecouplingProcessServlet.doPost(DecouplingProcessServlet.java:163)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
    at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:269)
    at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:81)
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at pk.vodafone.valves.PKAccessLogValve.invoke(PKAccessLogValve.java:547)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:724)
00:49:30,117 ERROR [CoyoteAdapter] An exception or error occurred in the container during the request processing
java.lang.NoClassDefFoundError: javax/servlet/ServletRequestAttributeEvent
    at org.apache.catalina.connector.Request.setAttribute(Request.java:1452)
    at org.apache.catalina.core.StandardWrapperValve.exception(StandardWrapperValve.java:523)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:280)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
    at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:269)
    at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:81)
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at pk.vodafone.valves.PKAccessLogValve.invoke(PKAccessLogValve.java:547)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.ClassNotFoundException: Unexpected error during load of: javax.servlet.ServletRequestAttributeEvent, msg=null
    at org.jboss.classloader.spi.base.ClassLoaderManager.process(ClassLoaderManager.java:173)
    at org.jboss.classloader.spi.base.BaseClassLoaderDomain.loadClass(BaseClassLoaderDomain.java:259)
    at org.jboss.classloader.spi.base.BaseClassLoaderDomain.loadClass(BaseClassLoaderDomain.java:1102)
    at org.jboss.classloader.spi.base.BaseClassLoader.loadClassFromDomain(BaseClassLoader.java:772)
    at org.jboss.classloader.spi.base.BaseClassLoader.loadClass(BaseClassLoader.java:415)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 19 more
Caused by: java.lang.OutOfMemoryError
    at java.util.zip.Inflater.init(Native Method)
    at java.util.zip.Inflater.<init>(Inflater.java:101)
    at java.util.zip.ZipFile.getInflater(ZipFile.java:450)
    at java.util.zip.ZipFile.getInputStream(ZipFile.java:369)
    at org.jboss.virtual.plugins.context.zip.ZipFileWrapper.openStream(ZipFileWrapper.java:214)
    at org.jboss.virtual.plugins.context.zip.ZipEntryContext.openStream(ZipEntryContext.java:1066)
    at org.jboss.virtual.plugins.context.zip.ZipEntryHandler.openStream(ZipEntryHandler.java:153)
    at org.jboss.virtual.VirtualFile.openStream(VirtualFile.java:230)
    at org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy.getResourceAsStream(VFSClassLoaderPolicy.java:483)
    at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.java:508)
    at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.java:506)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseClassLoader.java:504)
    at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseClassLoader.java:481)
    at org.jboss.classloader.spi.base.BaseDelegateLoader.loadClass(BaseDelegateLoader.java:134)
    at org.jboss.classloader.spi.filter.FilteredDelegateLoader.loadClass(FilteredDelegateLoader.java:131)
    at org.jboss.classloader.spi.base.ClassLoadingTask$ThreadTask.run(ClassLoadingTask.java:452)
    at org.jboss.classloader.spi.base.ClassLoaderManager.nextTask(ClassLoaderManager.java:258)
    at org.jboss.classloader.spi.base.ClassLoaderManager.process(ClassLoaderManager.java:152)
    ... 24 more
[thread 123611 also had an error]

我在这个主题上找到了几个有用的链接:

http://practicalcloudcomputing.com/post/444939181/outofmemoryjnigzip

http://www.javacodegeeks.com/2013/01/java-heap-space-native-heap-and-memory-problems.html

JVM选项如下:

-server -Xms2048m -Xmx2048m -XX:NewSize=384m 
-XX:MaxNewSize=384m 
-XX:SurvivorRatio=4 
-XX:MinHeapFreeRatio=11 
-XX:PermSize=80m 
-verbose:gc 
-XX:+PrintGCDateStamps 
-XX:+PrintGCDetails 
-XX:+DisableExplicitGC 
-Djava.awt.headless=TRUE -DUseSunHttpHandler=TRUE -Dsun.net.client.defaultConnectTimeout=25000 
-Dsun.net.client.defaultReadTimeout=50000 
-Dfile.encoding=UTF-8 
-Xloggc:gc.log 
Dcom.sun.management.jmxremote.port=9003 
-Dcom.sun.management.jmxremote.authenticate=FALSE 
-Dcom.sun.management.jmxremote.ssl=FALSE 
-Duser.language=de 
-Duser.region=DE 
-Duser.country=DE 
-Djboss.vfs.cache.TimedPolicyCaching.lifetime=1440000 
-DVFjavaWL=er.core.de

更新

再分析一下。这是我对 xml 解析发生的事情的天真解释:

  1. 我们有一个单例JAXBHelper 类,带有实例级JAXBContext(这是一个线程安全对象)。
  2. 每次收到请求时,我们都会尝试将传入的 xml 字符串绑定(bind)到 Java 对象(之前由 JAXB 从 xsd 生成)。
  3. bind 方法创建一个实例级解码器(这些不是线程安全的,但创建起来很便宜)。
  4. 绑定(bind)方法然后调用解码器的 unmarshal(InputStream) 方法。
  5. 现在 javax.xml.bind.helpers.AbstractUnmarshallerImpl 然后调用 SAXParserFactory.newInstance,后者又调用类加载器,后者又需要一个 Inflater

当然,实现(我们使用的是 jaxb-ri 2.2.7)应该保留 SAXParserFactory 或 SAXParser 并重新使用它们?我注意到两者都不是线程安全的,因此可以使用 ThreadLocal 来完成。或者可以重新使用 Inflater 实例吗?

这些没有被重新使用的事实是否意味着我没有取消引用我的对象? UnMarshaller 似乎没有任何类型的关闭方法。

最佳答案

内存泄漏是由未关闭的Inflaters引起的。
看起来这些膨胀器落到了老年代,只要不触发 Full GC,它们的终结器就不会被调用。

为了防止 JRE 扫描所有 JAR 文件以寻找 SAXParserFactory,您可以创建包含以下行的 $JAVA_HOME/jre/lib/jaxp.properties 文件:

javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl

删除 -XX:+DisableExplicitGC 选项可能也很有用,因为 JVM 运行时在检测到 native 内存不足时依赖于 System.gc 调用。

关于java - 从 Java 6 升级到 Java 7 时 native 堆上出现 OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28148785/

相关文章:

java - 如何为列表 JAXB 制作 setter

java - 如果 JVM 在进行 GC 时不断移动对象,它如何解析引用?

c# - 垃圾收集会处理列表列表的值吗

c# - 当 GC 调用 Object.Finalize 时,子对象是否仍然存在?

java - 将多参数 matches() 从 EasyMock 1 ArgumentsMatcher 转换为 EasyMock 2/3 IArgumentMatcher

java - JAXB 构造函数注入(inject)

java - MOXy 的 xml-transient 声明是如何工作的?

java - 字符串是 Java 中的对象,那我们为什么不使用 'new' 来创建它们呢?

java - 使用 java 从网站下载文件

java - Eclipse 菜单管理器 : get ImageDescriptor of Image?