JAVAのメモリリーク調査

序文

以前仕事中に書いたブログ投稿の一部がブログに同期されませんでした。この記事は、読者にインスピレーションを与えることを目的として、1 年以上前に書かれた可能性があります。

まずはプロジェクトの背景をご紹介します。私たちのプロジェクトは Tomcat にデプロイされています。1 つの Tomcat の下で複数の Java プロジェクトが実行されています。再デプロイ (war パッケージを webapps ディレクトリに直接スローする) と、プロジェクトが長時間実行されることがよくあります。そして、フォローアップの解決策は次のとおりです。通常は Tomcat を再起動します。
これは私が行ったトラブルシューティングの試みです。

1. まず、Tomcat マネージャー インターフェイスを開きます。

具体的な手順は次のとおりです。

  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 [マネージャー アプリ] をクリックします:

ここに画像の説明を挿入

  1. プロジェクトを再デプロイし、「リークの検索」ボタンをクリックします。

ここに画像の説明を挿入

  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"   

最初のホスト名は IP である必要があり、2 番目に 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