目录
- 1. 说明
- 2. 代码模拟
- 3. AB压测模拟
- 4. 分析
- 5. 分析dump *.hprof文件工具
-
- 5.1. visualVM
- 5.2. MAT
- 5.3. 在线分析工具
- 6. OQL语法例子
- 7. 解决异常情况的方法
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. 分析
-
当我们发现机器内存持续上升时, 我们可以用top命令来定位java程序
-
我们可以通过top -Hp 查看每个线程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
- 导入dump文件 我们可以看到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安装路径》