• 一个java内存泄漏的排查案例


    这是个比较典型的java内存使用问题,定位过程也比较直接,但对新人还是有点参考价值的,所以就纪录了一下。

    下面介绍一下在不了解系统代码的情况下,如何一步步分析和定位到具体代码的排查过程
    (以便新人参考和自己回顾)

    初步的现象

    业务系统消费MQ中消息速度变慢,积压了200多万条消息,通过jstat观察到业务系统fullgc比较频繁,到最后干脆OOM了:

    进一步分析

    既然知道了内存使用存在问题,那么就要知道是哪些对象占用了大量内存.

    很多人都会想到把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程太折腾不到万不得已最好别这么干。

    可以用更轻量级的在线分析,用jmap查看存活的对象情况(jmap -histo:live [pid]),可以看出HashTable中的元素有5000多万,占用内存大约1.5G的样子:

    定位到代码

    现在已经知道了是HashTable的问题,那么就要定位出什么代码引起的

    接下来自然要看看是什么代码往HashTable里疯狂的put数据,于是用神器btrace跟踪Hashtable.put调用的堆栈。

    首先写btrace脚本TracingHashTable.java:

    import com.sun.btrace.annotations.*;
    import static com.sun.btrace.BTraceUtils.*;
    
    @BTrace
    public class TracingHashTable {
            /*指明要查看的方法,类*/
            @OnMethod(
                clazz="java.util.Hashtable",
                method="put",
                location=@Location(Kind.RETURN))
            public static void traceExecute(@Self java.util.Hashtable object){
                    println("调用堆栈!!");
                    jstack();
            }
    }

    然后运行:
    bin/btrace -cp build 4947 TracingHashTable.java

    看到有大量类似下图的调用堆栈

    可以看出是在接收到消息后查询入库的代码造成的,业务方法调用ibatis再到mysql jdbc驱动执行statement时put了大量的属性到HashTable中。

    通过以上排查已基本定位了由那块代码引起的,接下来就是打开代码工程进行白盒化改造了,对相应代码进行优化(不在本文范围内了。几个图中的pid不一致就别纠结了,有些是系统重启过再截图的).

    本文永久链接: http://jenwang.me/14853486232080.html

  • 相关阅读:
    基于【 Docker】四 || Docker常用镜像安装
    【静态延迟加载】self关键字和static关键字的区别
    【php设计模式】单例模式
    为什么要使用 SPL中的 SplQueue实现队列
    php中连接tcp服务的三种方式
    使用rsync工具构建php项目管理平台
    php 求两个数组的差集应该注意的事情
    lnmp环境快速搭建及原理解析
    nginx + lua 限制ip地址访问
    mysql主从复制搭建
  • 原文地址:https://www.cnblogs.com/huanglog/p/10304949.html
Copyright © 2020-2023  润新知