4

Open J2EE Web 模板是 wicket 的展示应用程序 - 带有 Spring 和 Hibernate 的 JPA,在 Tomcat7 servlet 容器上运行。它的 Maven 构建脚本似乎以标准方式使用组件。

但是,当它从 Tomcat 取消部署时,它会受到应用程序类加载器内存泄漏的影响。

Tomcat 的“查找泄漏”按钮确认泄漏。当使用 VM 选项 -XX:+HeapDumpOnOutOfMemoryError 部署在 Tomcat 上时,可以使用 Eclipse Memory Analyzer Tool (MAT) 分析生成的堆转储。MAT 将类标识java.util.logging.Level$KnownLevel为阻止垃圾收集的罪魁祸首。

构造函数的调试KnownLevel显示以下堆栈跟踪:

java.util.logging.Level$KnownLevel.add(Level.java:477) java.util.logging.Level.(Level.java:212) java.util.logging.Level.(Level.java:190) 组织。 jboss.logging.JDKLevel.(JDKLevel.java:35) org.jboss.logging.JDKLevel.(JDKLevel.java:42) org.jboss.logging.JDKLogger.translate(JDKLogger.java:78) org.jboss.logging。 JDKLogger.isEnabled(JDKLogger.java:85) org.jboss.logging.Logger.debugf(Logger.java:563) org.jboss.logging.LoggerProviders.find(LoggerProviders.java:37) org.jboss.logging.LoggerProviders。 (LoggerProviders.java:32) org.jboss.logging.Logger.getLogger(Logger.java:2163) org.jboss.logging.Logger.getMessageLogger(Logger.java:2259) org.jboss.logging.Logger.getMessageLogger(Logger .java:2214) org.hibernate.ejb.Ejb3Configuration.(Ejb3Configuration.java:144) org.hibernate.ejb.HibernatePersistence。createContainerEntityManagerFactory(HibernatePersistence.java:74) org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268) org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) org.springframework.beans。 factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) org.springframework.beans.factory.support.AbstractAutowireAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) java:519) org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory。createBean(AbstractAutowireCapableBeanFactory.java:456) org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) org .springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) org.springframework.beans.factory.support.DefaultListableBeanFactory .preInstantiateSingletons(DefaultListableBeanFactory.java:567) org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385) org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284) org.springframework.web.context.ContextLoaderListener。 contextInitialized(ContextLoaderListener.java:111) org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)

如果我正确理解了类加载器泄漏:可怕的“java.lang.OutOfMemoryError: PermGen space”异常,那么这个类加载器泄漏是可以预料的。

避免这种情况的推荐方法是什么,或者 Tomcat 上的替代 Spring/JPA 模板 Web 应用程序是什么?

4

2 回答 2

3

我在 Tomcat7 + OpenJPA2.4.1 + ValidationAPI1.x + hibernate-validator-5.2.1 + jboss-logging.jar 上看到了同样的 webapp 内存泄漏

问题确实是 jboss-logging.jar 创建了 java.util.logging.Level 实例的子类。如果 jar 由 J2EE 容器提供,则可能不是问题,但会在 mywebapp/WEB-INF/lib 分发中发生。我创建了一个包的分支来禁用子类化。问题消失了,webapp 热重新部署工作正常。

GC 根路径的 Heapdump 表明问题的根源,JDKLevel 子类将 webapp 保留在内存中,很快 JVM 就会耗尽 PermGen 内存。

this     - value: org.apache.catalina.loader.WebappClassLoader #2
 <- <classLoader>     - class: org.jboss.logging.JDKLevel, value: org.apache.catalina.loader.WebappClassLoader #2
  <- <class>     - class: org.jboss.logging.JDKLevel, value: org.jboss.logging.JDKLevel class JDKLevel
   <- levelObject     - class: java.util.logging.Level$KnownLevel, value: org.jboss.logging.JDKLevel #6
    <- [1]     - class: java.lang.Object[], value: java.util.logging.Level$KnownLevel #12
     <- elementData     - class: java.util.ArrayList, value: java.lang.Object[] #5160 (10 items)
      <- value     - class: java.util.HashMap$Entry, value: java.util.ArrayList #3532
       <- [0]     - class: java.util.HashMap$Entry[], value: java.util.HashMap$Entry #21639
        <- table     - class: java.util.HashMap, value: java.util.HashMap$Entry[] #280 (16 items)
         <- intToLevels (sticky class)     - class: java.util.logging.Level$KnownLevel, value: java.util.HashMap #375

编辑为此错误创建的 JBoss Jira 票证 ( https://issues.jboss.org/browse/JBLOGGING-118 )

于 2015-09-05T12:20:40.543 回答
1

配置除 java.util.logging 之外的日志框架,例如Logback

如果根本没有配置日志记录,或者如果配置了 java.util.logging,jboss 日志记录将通过 JDK 错误Level.known 造成类加载器泄漏可以泄漏内存。请参阅 jboss 日志记录创建自定义 java.util.logging.Level 的问题中的堆栈跟踪。

于 2013-08-16T21:20:43.760 回答