首页 > 解决方案 > Tomcat 7 WeaAppClassLoader 与 Jersey 2 泄漏

问题描述

我正在使用以下配置遇到明显的 ClassLoader 泄漏:

我有一个简单的应用程序:

应用配置:

@ApplicationPath("/service")
public class ApplicationConfig extends Application {
    
    public ApplicationConfig() {
    }
    
    @Override
    public Set<Class<?>> getClasses(){
        Set<Class<?>> resources = new java.util.HashSet<>();
        
        resources.add(org.mdeggers.cplanapi.resource.CostInfoResource.class);
        resources.add(org.mdeggers.cplanapi.resource.InstituteInfoResource.class);
        resources.add(org.mdeggers.cplanapi.resource.InstituteTypeInfoResource.class);
        
        resources.add(org.mdeggers.cplanapi.mapper.NotFoundExceptionMapper.class);
        
        return resources;
    }
}

三种资源之一:

@Path("/v1/inst")
public class InstituteInfoResource {

    public InstituteInfoResource() {
    }

    @GET
    @Path("info")
    @Produces({MediaType.APPLICATION_JSON})
    public InstituteContainer getNationalList() {
        InstituteInfo instituteinfo = new InstituteInfo();
        return instituteinfo.getNational();
    }

    @GET
    @Path("info/{ state : [A-Z]{2} }")
    @Produces({MediaType.APPLICATION_JSON})
    public InstituteContainer getStateList(@PathParam("state") String state) {
        InstituteInfo instituteinfo = new InstituteInfo();
        return instituteinfo.getState(state);
    }
}

InstituteInfo 类是一个 DAO,它向 MySQL 数据库发出请求并返回一个包含信息的容器。

这一切都有效,但在卸载 Tomcat 管理器时抱怨卸载 Web 应用程序后存在泄漏。

执行堆转储并在 Eclipse MAT 中使用以下 OQL 查看它表明应用程序仍驻留在内存中,started=false。

SELECT wcl.contextName.toString() AS contextName,
   wcl.started AS started,
   wcl.@retainedHeapSize AS retainedSize
FROM org.apache.catalina.loader.WebappClassLoader wcl
上下文名称 开始 保留大小
/cplanapi 错误的 586,720
/文档 真的 46,664
/主机管理器 真的 47,288
/经理 真的 47,392
/例子 真的 85,432
真的 46,912

cplanapi 的 GC 根是:

class com.sun.naming.internal.ResourceManager       
'- propertiesCache java.util.WeakHashMap                         
   '- table java.util.WeakHashMap$Entry[16]                      
      '- [13] java.util.WeakHashMap$Entry                         
         '- referent org.apache.catalina.loader.WebappClassLoader

这发生在 Windows 和 Linux 以及上述 JRE 和 Java 1.8.0_202 上。

任何有关如何解决此问题的想法将不胜感激。

启动日志 (JRE 11)

Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version name:   Apache Tomcat/7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server built:          Nov 18 2020 12:18:55 UTC
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version number: 7.0.107.0
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Name:               Windows 10
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Version:            10.0
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Architecture:          amd64
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Java Home:             D:\Programs-x64\Java\jdk-11.0.10+9-jre
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Version:           11.0.10+9
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Vendor:            AdoptOpenJDK
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_BASE:         D:\Programs\Apache\apache-tomcat-7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_HOME:         D:\Programs\Apache\apache-tomcat-7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djava.util.logging.config.file=D:\Programs\Apache\apache-tomcat-7.0.107\conf\logging.properties
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcom.sun.management.jmxremote
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcom.sun.management.jmxremote.port=9005
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcom.sun.management.jmxremote.ssl=false
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcom.sun.management.jmxremote.authenticate=false
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -DRDS_HOSTNAME=localhost
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dignore.endorsed.dirs=
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.base=D:\Programs\Apache\apache-tomcat-7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.home=D:\Programs\Apache\apache-tomcat-7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djava.io.tmpdir=D:\Programs\Apache\apache-tomcat-7.0.107\temp
Jan 31, 2021 10:09:19 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: Loaded Apache Tomcat Native library [1.2.25] using APR version [1.7.0].
Jan 31, 2021 10:09:19 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
Jan 31, 2021 10:09:19 AM org.apache.catalina.core.AprLifecycleListener initializeSSL
INFO: OpenSSL successfully initialized [OpenSSL 1.1.1g  21 Apr 2020]
Jan 31, 2021 10:09:19 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-apr-8080"]
Jan 31, 2021 10:09:19 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-apr-127.0.0.1-8009"]
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 644 ms
Jan 31, 2021 10:09:19 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Catalina]
Jan 31, 2021 10:09:19 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.107
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\docs]
Jan 31, 2021 10:09:19 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:20 AM org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
WARNING: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [457] milliseconds.
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\docs] has finished in [905] ms
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\examples]
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\examples] has finished in [344] ms
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\host-manager]
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\host-manager] has finished in [146] ms
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\manager]
Jan 31, 2021 10:09:20 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:21 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\manager] has finished in [148] ms
Jan 31, 2021 10:09:21 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\ROOT]
Jan 31, 2021 10:09:21 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:21 AM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\ROOT] has finished in [136] ms
Jan 31, 2021 10:09:21 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-apr-8080"]
Jan 31, 2021 10:09:21 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-apr-127.0.0.1-8009"]
Jan 31, 2021 10:09:21 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1766 ms

部署

Jan 31, 2021 10:09:49 AM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deploying web application archive [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\cplanapi.war]
Jan 31, 2021 10:09:50 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 31, 2021 10:09:53 AM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deployment of web application archive [D:\Programs\Apache\apache-tomcat-7.0.107\webapps\cplanapi.war] has finished in [3,558] ms

取消部署

Jan 31, 2021 10:10:27 AM org.apache.catalina.startup.HostConfig undeploy
INFO: Undeploying context [/cplanapi]

关闭

Jan 31, 2021 10:10:37 AM org.apache.catalina.core.StandardServer await
INFO: A valid shutdown command was received via the shutdown port. Stopping the Server instance.
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol pause
INFO: Pausing ProtocolHandler ["http-apr-8080"]
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol pause
INFO: Pausing ProtocolHandler ["ajp-apr-127.0.0.1-8009"]
Jan 31, 2021 10:10:37 AM org.apache.catalina.core.StandardService stopInternal
INFO: Stopping service [Catalina]
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol stop
INFO: Stopping ProtocolHandler ["http-apr-8080"]
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol stop
INFO: Stopping ProtocolHandler ["ajp-apr-127.0.0.1-8009"]
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol destroy
INFO: Destroying ProtocolHandler ["http-apr-8080"]
Jan 31, 2021 10:10:37 AM org.apache.coyote.AbstractProtocol destroy
INFO: Destroying ProtocolHandler ["ajp-apr-127.0.0.1-8009"]

Web 应用程序中似乎没有任何问题。

标签: javaresttomcatjersey

解决方案


在 Tomcat 邮件列表上的 Mark Thomas 发表了一些评论后,我设法找到了问题(有两个)。诀窍是在 GC ROOT 分析中排除软引用以揭示真正的罪魁祸首。

杰克逊缓冲区泄漏

错误报告中给出了对此的修复。基本上,您必须设置一个系统属性,并添加一个 servlet 上下文侦听器以在关闭 Web 应用程序之前清除缓冲区。

log4j2 JMX 泄漏

这被标记为已关闭/已修复,但似乎并非如此。通过使用另一个系统属性(暂时)关闭 log4j 的 JMX 可以解决此问题。


推荐阅读