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

1. 说明

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

2. 代码模拟

通过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";
    }
}

3. AB压测模拟

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

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

4. 分析

  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为输出文件

5. 分析dump *.hprof文件工具

5.1. visualVM

或者使用java默认的 通过jvisualvm 命令

下载地址:https://visualvm.github.io/download.html

  1. 导入dump文件
    在这里插入图片描述
    这里可以分析线程和内存对象情况,我们切换到Object
    在这里插入图片描述
    我们可以看到Byte占用了90%以上的内存 我们可以查看引用对象
    在这里插入图片描述
    在这里插入图片描述
    看到引用对象是ThreadLocal 所以判定是使用ThreadLocal 使用完毕并没有释放导致内存泄露

5.2. MAT

在这里插入图片描述
下载地址

5.3. 在线分析工具

https://heaphero.io/heap-report2_0.jsp
在这里插入图片描述

6. OQL语法例子

select t from freemarker.core.SimpleCharStream
WHERE toString(s.value) LIKE ".*Test"
SELECT s, toString(s.value), toString(s.name) FROM com.xxxx.XXX s
WHERE toString(s.value) LIKE ".*Test"
select  t from java.lang.String t
where toString(t.value)=='合伙人-云领天下'
SELECT toString(t.value) FROM java.lang.String t WHERE (toString(t.value) LIKE "select.*")
SELECT toString(t.value) FROM java.lang.String t WHERE (toString(t.value) LIKE "select.*") or (toString(t.value) LIKE "SELECT.*")

7. 异常情况解决方式

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安装路径》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值