• JVM监控-内存泄露与高CPU占用排查(九)


    说明

    一般我们发现内存持续增长,但是并没有得到释放,我们就需要排查是否内存泄露

    代码模拟

    通过ThreadLocal模拟内存泄露  

    为什么ThreadLocal会内存泄露?参考:《ThreadLocal》

    @RequestMapping("/testController")
    @Controller
    public class TestController {
    
        @RequestMapping(value = "/test3")
        @ResponseBody
        public String test3() {
            ThreadLocal localVariable = new ThreadLocal();
            localVariable.set(new Byte[4096 * 1024]);// 为线程添加变量
            return "success";
        }
    }

    AB压测模拟

    ab使用例子:《压测工具-ab》

    ab -c 500 -n 1000 localhost:8999/testController/test3

    分析

    1.当我们发现机器内存持续升高 我们可以使用top命令来定位java程序

      

    2.我们可以通过top -Hp 查看各个线程cpu 和 内存占用情况

    红框框起来的内存是我有个疑惑,应该是各个线程占用的内存,但是这里好像显示的是总内存;可能是因为堆内存是线程共享 所以这里显示的是总的堆占用内存。

    3.我们可以通过jstack dump到线程堆栈,对于分析线程死锁 cpu占用过高代码定位很有帮助

    这里我们以21141为例,先将21141转换为16进制:在线转换 得到5295 通过jstack dump线程堆栈信息 

    或者通过命令 printf  '%x/n' tid 把线程id转化为十六进制

    jstack 19751|grep -A20 5295 //查找5295 并打印后20行 19751为PID 5295 为线程id 16进制
    jstack 19751|grep -A20 5295  >/root/threaddump.txt//查找5295 并打印后20行 并输出到指定文件 
    jstack 19751  >/root/threaddump.txt// dump整个线程堆栈并输出到指定文件

    可以发现该线程一直处于 TIMED_WAITING 状态  此时 CPU 使用率和负载并没有出现异常,我们可以排除死锁或 I/O 阻塞的异常问题了。

    4.通过jmap或者jstack查看堆内存使用情况

    参数详解请看:《jvm-内存监控工具》

    可以发现,老年代的使用率几乎快占满了,而且内存一直得不到释放

     ./jmap -heap  19751
     ./jstack -gc 19751

     5.查看gc信息

    参数详解请看:《jvm-内存监控工具》

    jstat -gcutil pid  1000//1秒一次采集gc信息

     6.我们可以通过jmap查看内存存活对象情况

    可以发现[Ljava.lang.Byte; 有161个实例 占用了大量空间

    jmap -histo  pid   所有对象创建数量
    jmap -histo:live pid 只查看存活对象
    jmap -histo  pid  >/root/object.txt 所有对象创建数量并保存到指定文件
    jmap -histo:live pid /root/object.txt 只查看存活对象并保存到指定文件

    7.dump内存信息进行分析参考:《JVM学习-内存监控工具(五)-dump内存信息》

    jmap -dump:format=b,file=/Users/liqiang/Desktop/logs/heap.hprof  pid ///Users/liqiang/Desktop/logs/heap.hprof为输出文件

    分析dump文件工具

    visualVM

    1导入dump文件

     这里可以分析线程和内存对象情况,我们切换到Object

     

    我们可以看到Byte占用了90%以上的内存 我们可以查看引用对象

     

     看到引用对象是ThreadLocal 所以判定是使用ThreadLocal 使用完毕并没有释放导致内存泄露

    MAT

    下载地址需要翻墙 暂时不测试了

    异常情况解决方式

    1.Unable to open socket file: target process not responding or HotSpot VM not loaded The -F option can be used when the target process is not responding

    切换到程序所在的用户

    2.注:如果使用jmap和jstack报错 可能是多jdk导致切换当前使用jdk 在bin下面通过./指定调用:参考《linux查看jdk安装路径》

  • 相关阅读:
    聊聊CMDB的前世今生
    我是如何走上运维岗位的?谈谈新人入职运维发展的注意事项
    如何从生命周期的视角看待应用运维体系建设?
    标准化体系建设(下):如何建立基础架构标准化及服务化体系?
    标准化体系建设(上):如何建立应用标准化体系和模型?
    微服务架构时代,运维体系建设为什么要以“应用”为核心?
    Kubernetes容器化工具Kind实践部署Kubernetes v1.18.x 版本, 发布WordPress和MySQL
    Etcd常用运维命令
    Logstash生产环境实践手册(含grok规则示例和ELKF应用场景)
    Netflix业务运维分析和总结
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12935404.html
Copyright © 2020-2023  润新知