宽厚的肩膀 發表於 2026-1-13 08:38:33

JVM内存与CPU占用过高问题定位及解决

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>前言</li><li>一、示例代码</li><li>二、运行代码</li><li>三、top命令</li><li>四、问题定位</li><ul class="second_class_ul"><li>1、查看java进程所有的线程列表</li><li>2、输出线程882292十六进制</li></ul><li>五、输出java堆栈信息</li><ul class="second_class_ul"></ul><li>六、pid_882245_dump.txt</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>前言</h2>
<p>如果开发过程中代码存在不规范漏洞,Java程序在运行时就很有可能会出现:内存(溢出、泄漏)、CPU占用过高。</p>
<p>本篇文章将通过一个简单的例子给大家演示一下,如果线上出现以上问题我们可以如何精准定位到代码上的问题。</p>
<p><strong>排查思路:进程-&gt;线程-&gt;代码-&gt;类-&gt;方法</strong></p>
<p class="maodian"></p><h2>一、示例代码</h2>
<p>模拟一个线程往一个集合List&lt;byte[]&gt; list中无限循环添加byte[],这样就可以有效的观察到java进程运行时会出现CPU、内存占用过高的场景。然后给当前运行的线程自定一个线程名称,便于后续问题排查。</p>
<div class="jb51code"><pre class="brush:java;">package com.nb.java;

import java.util.ArrayList;
import java.util.List;

@SpringBootApplication
public class JavaBasisApplication {
        public static void main(String[] args) {
                // 定义一个list
                List&lt;byte[]&gt; list = new ArrayList&lt;&gt;();
      // 创建一个线程,并且自定义这个线程的名称:模拟Java运行时CPU、内存占用过高的线程
                new Thread(() -&gt; {
                        while (true){
                                System.out.println("===每次添加一个byte字节数组===");
                                list.add(new byte);
                        }
                },"模拟Java运行时CPU、内存占用过高的线程").start();
        }
}
</pre></div>
<p class="maodian"></p><h2>二、运行代码</h2>
<p>1、将上面的类基于SpringBoot打包成一个jar包,随便放到一个服务器运行。</p>
<p>执行以下命令:</p>
<div class="jb51code"><pre class="brush:java;">nohup java -jar java.jar &gt; test.log 2&gt;&amp;1 &amp;
</pre></div>
<p>2、查询当前运行的java程序进程PID:882245</p>
<div class="jb51code"><pre class="brush:java;">jps -l
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011211023175.jpg" /></p>
<p class="maodian"></p><h2>三、top命令</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011211023191.jpg" /></p>
<ul><li>CPU=262.4%</li><li>MEM=5.3%</li></ul>
<p>通过top命令可以发现882245这个进程(也就是我们运行的这个java程序)占用的CPU和内存相对来说都是比较高的。</p>
<p class="maodian"></p><h2>四、问题定位</h2>
<p class="maodian"></p><h3>1、查看java进程所有的线程列表</h3>
<div class="jb51code"><pre class="brush:java;">top -p 882245 -H
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011211023181.jpg" /></p>
<p>从这个图可以看出我们运行的java程序里出现了882292线程占用CPU、内存过高。到这里我们就成功了一半。至少看到了是那个线程出现的问题。</p>
<p class="maodian"></p><h3>2、输出线程882292十六进制</h3>
<div class="jb51code"><pre class="brush:java;">printf "%x\n" 882292
</pre></div>
<p>d7674(882292的十六进制的值,用于后面查看线程堆栈中的关键字检索)</p>
<p class="maodian"></p><h2>五、输出java堆栈信息</h2>
<p>注意:这里的882245是进程ID,不是线程ID。</p>
<div class="jb51code"><pre class="brush:java;">jstack 882245 &gt; pid_882245_dump.txt
</pre></div>
<p>在当前目录会生成一个pid_882245_dump.txt 文件。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011211023110.jpg" /></p>
<p class="maodian"></p><h2>六、pid_882245_dump.txt</h2>
<div class="jb51code"><pre class="brush:java;">cat pid_882245_dump.txt | grep d7674 -B 30
</pre></div>
<p>这里的(d7674)就是第四部生成的。</p>
<div class="jb51code"><pre class="brush:java;">root@yiliao:~# cat pid_882245_dump.txt | grep d7674 -A 30
"模拟Java运行时CPU、内存占用过高的线程" #31 prio=5 os_prio=0 cpu=1117037.88ms elapsed=1168.34s tid=0x00007efd81e31000 nid=0xd7674 runnable
   java.lang.Thread.State: RUNNABLE
        at java.io.FileOutputStream.writeBytes(java.base@11.0.19/Native Method)
        at java.io.FileOutputStream.write(java.base@11.0.19/FileOutputStream.java:354)
        at java.io.BufferedOutputStream.flushBuffer(java.base@11.0.19/BufferedOutputStream.java:81)
        at java.io.BufferedOutputStream.flush(java.base@11.0.19/BufferedOutputStream.java:142)
        - locked &lt;0x0000000413bcfa60&gt; (a java.io.BufferedOutputStream)
        at java.io.PrintStream.write(java.base@11.0.19/PrintStream.java:561)
        - locked &lt;0x00000004119f6828&gt; (a java.io.PrintStream)
        at sun.nio.cs.StreamEncoder.writeBytes(java.base@11.0.19/StreamEncoder.java:233)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(java.base@11.0.19/StreamEncoder.java:312)
        at sun.nio.cs.StreamEncoder.flushBuffer(java.base@11.0.19/StreamEncoder.java:104)
        - locked &lt;0x00000004119f67e0&gt; (a java.io.OutputStreamWriter)
        at java.io.OutputStreamWriter.flushBuffer(java.base@11.0.19/OutputStreamWriter.java:181)
        at java.io.PrintStream.write(java.base@11.0.19/PrintStream.java:606)
        - eliminated &lt;0x00000004119f6828&gt; (a java.io.PrintStream)
        at java.io.PrintStream.print(java.base@11.0.19/PrintStream.java:745)
        at java.io.PrintStream.println(java.base@11.0.19/PrintStream.java:882)
        - locked &lt;0x00000004119f6828&gt; (a java.io.PrintStream)
        at com.nb.java.JavaBasisApplication.lambda$main$0(JavaBasisApplication.java:30)
        at com.nb.java.JavaBasisApplication$$Lambda$634/0x00000008403d2c40.run(Unknown Source)
        at java.lang.Thread.run(java.base@11.0.19/Thread.java:829)

"DestroyJavaVM" #32 prio=5 os_prio=0 cpu=2896.41ms elapsed=1168.34s tid=0x00007efd80015000 nid=0xd7646 waiting on condition
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #33 daemon prio=9 os_prio=0 cpu=1.12ms elapsed=18.83s tid=0x00007efd18001000 nid=0xd76d7 waiting on condition
   java.lang.Thread.State: RUNNABLE

"VM Thread" os_prio=0 cpu=781.96ms elapsed=1171.43s tid=0x00007efd802a6000 nid=0xd764c runnable
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011211023187.jpg" /></p>
<p>从图上下面的剪头指向就很写清楚定位到:com.nb.java.JavaBasisApplication#main方法有问题。这样就定位到我们的具体代码。</p>
<p class="maodian"></p><h2>总结</h2>
<p>以上为个人经验,希望能给大家一个参考,也希望大家多多支持琼殿技术社区。</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>JVM五大内存区域使用及说明</li><li>Java中的JVM内存分析与故障排查指南</li><li>k8s之容器内存与JVM内存解读</li><li>Java内存分配与JVM参数详解(推荐)</li><li>解决OOM:JVM内存不足问题</li><li>Java之JVM的内存分析(简单版+案例)</li><li>JVM内存划分机制的使用详解</li><li>JVM内存管理:OutOfMemoryError异常的问题</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: JVM内存与CPU占用过高问题定位及解决