一次JAVA内存泄露排查

前言

有些以前工作时写的博文,没有同步到博客过来。这一篇可能是1年多前写的,希望能给读者一些启示。

首先要介绍下项目的背景。我们的项目是部署到tomcat的,一个tomcat下有若干的Java项目在跑,我们发现在每次重新部署(把war包直接丢进webapps目录下)项目时经常会出现长时间卡顿等现象,并且后续的解决方案一般是重启tomcat。
这个是我做的一次排查尝试。

1. 首先开启tomcat manager界面。

具体步骤为:

  1. /tomcat/conf/tomcat-users.xml添加:
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
  1. CATALINA_HOME/webapps/manager/META-INF/context.xml,注释远程连接限制:
<Context antiResourceLocking="false" privileged="true" >
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
</Context
  1. 访问 远程主机:8080 点击Manager App:

在这里插入图片描述

  1. 重新部署某个项目,然后点击Find leaks按钮:

在这里插入图片描述

  1. 查看提示是否存在内存泄露:

在这里插入图片描述

2. 查看服务器状态

在这里插入图片描述

查看内存状态:

在这里插入图片描述

3. 配置 JMX

无密码

  1. 编辑 /tomcat/bin/setenv.sh
 #!/bin/sh
 JAVA_OPTS="$JAVA_OPTS  -Dcom.sun.management.jmxremote
 -Dcom.sun.management.jmxremote.ssl=false
 -Djava.rmi.server.hostname=120.25.205.78                                                  -Dcom.sun.management.jmxremote.authenticate=false
 -Dcom.sun.management.jmxremote.port=18889"
 
 #JAVA_OPTS="$JAVA_OPTS  -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management. j mxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -Dcom.sun.manag em ent.jmxremote.port=18889"   

注意首先 hostname必须是IP,其次不能是127.0.0.1。如果是虚拟机之类的,可以使用内网地址也就是类似于192.168.1.3之类的。 云服务器之类的填外网地址。

  1. 重启tomcat。

有密码

  1. 编辑 /tomcat/bin/setenv.sh
 #!/bin/sh
 JAVA_OPTS="$JAVA_OPTS  -Dcom.sun.management.jmxremote
 -Dcom.sun.management.jmxremote.ssl=false
 -Djava.rmi.server.hostname=xxx                                                 -Dcom.sun.management.jmxremote.authenticate=true
 -Dcom.sun.management. j mxremote.password.file=../conf/jmxremote.password 
 -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
 -Dcom.sun.management.jmxremote.port=18889"
  1. 创建/编辑 /tomcat/conf/jmxremote.password 账号 权限
monitorRole readonly                                                                      controlRole readwrite
  1. 创建/编辑 /tomcat/conf/jmxremote.access 账号 密码
 monitorRole tomcat
 controlRole tomcat
  1. 修改读写权限:
chmod 600 jmxremote.access 
chmod 600 jmxremote.password 
  1. 重启tomcat

故障分析

可以借助Telnet看端口是否能用。不能用的话看看防火墙之类的问题。

4. 配置 jstat

  1. 确认环境变量JAVA_HOME是否存在。和jdk安装方式有关系。
export | grep JAVA_HOME
  1. 有输出代表有这个变量,那么下一步我们要创建一个jstatd.all.policy文件。
mkdir -p /etc/java/
cd /etc/java/
(sudo) vim jstatd.all.policy
  1. 编辑文件jstatd.all.policy,可以看到之所以要确认是否有JAVA_HOME是为了文件内容的引用。
grant codebase "file:${java.home}/../lib/tools.jar" { 
   permission java.security.AllPermission; 
};
  1. 启动
jstatd -J-Djava.security.policy=jstatd.all.policy -J Djava.rmi.server.hostname=xxx &

5. 分析Tomcat 日志

问题:

 A web application appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.

在这里插入图片描述

解决:

  • 升级mysql-connector-java

  • 引入

    @Component
    public class ShutdownListener implements ServletContextListener {
          
          
        @Override
        public void contextInitialized(ServletContextEvent sce) {
          
          
    
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
          
          
            AbandonedConnectionCleanupThread.checkedShutdown();
        }
    }
    

    参考:https://bugs.mysql.com/bug.php?id=69526

热部署现象

用visualvm观察部署一个存在内存泄露的项目:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/sayWhat_sayHello/article/details/119884867