25 | 内存持续上升,我该如何排查问题?
25 | 内存持续上升,我该如何排查问题?
讲述:李良
时长09:32大小6.54M
常用的监控和诊断内存工具
Linux 命令行工具之 top 命令
Linux 命令行工具之 vmstat 命令
Linux 命令行工具之 pidstat 命令
JDK 工具之 jstat 命令
JDK 工具之 jstack 命令
JDK 工具之 jmap 命令
实战演练
总结
思考题
赞 18
提建议
精选留言(35)
- 每天晒白牙2019-07-18放两篇自己在工作中排查JVM问题的两篇文章【非广告,纯技术文】 https://mp.weixin.qq.com/s/ji_8NhN4NnEHrfAlA9X_ag https://mp.weixin.qq.com/s/IPi3xiordGh-zcSSRie6nA
作者回复: 赞!
共 10 条评论90 - 我已经设置了昵称2019-07-18老师是否可以讲下如何避免threadLocal内存泄漏呢
作者回复: 我们知道,ThreadLocal是基于ThreadLocalMap实现的,这个Map的Entry继承了WeakReference,而Entry对象中的key使用了WeakReference封装,也就是说Entry中的key是一个弱引用类型,而弱引用类型只能存活在下次GC之前。 如果一个线程调用ThreadLocal的set设置变量,当前ThreadLocalMap则新增一条记录,此时ThreadLocal实例没有外部强引用,当发生一次垃圾回收,此时key值被回收,而value值依然存在内存中,由于当前线程一直存在,所以value值将一直被引用。. 这些被垃圾回收掉的key就存在一条引用链的关系一直存在:Thread --> ThreadLocalMap-->Entry-->Value,这条引用链会导致Entry不会回收,Value也不会回收,但Entry中的Key却已经被回收的情况,造成内存泄漏。 我们只需要在使用完该key值之后,通过remove方法remove掉,就可以防止内存泄漏了。
共 11 条评论73 - WL2019-07-18请问一下老师内存泄露和内存溢出具体有啥区别,有点不太理解内存泄露的概念。
作者回复: 内存泄漏是指不再使用的对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费。例如,我们之前在第3讲中聊到的在Java6中substring方法可能会导致内存泄漏情况发生。当调用substring方法时会调用new string构造函数,此时会复用原来字符串的char数组,而如果我们仅仅是用substring获取一小段字符,而原本string字符串非常大的情况下,substring的对象如果一直被引用,由于substring的里面的char数组仍然指向原字符串,此时string字符串也无法回收,从而导致内存泄露。 内存溢出则是发生了OutOfMemoryException,内存溢出的情况有很多,例如堆内存空间不足,栈空间不足,以及方法区空间不足都会发生内存溢出异常。 内存泄漏与内存溢出的关系:内存泄漏很容易导致内存溢出,但内存溢出不一定是内存泄漏导致的。
共 2 条评论34 - 怪盗キッド2019-09-22我开源了一个 Java 性能监控工具,就是用 JDK 自带的接口实现的。 GitHub 地址:https://github.com/LinShunKang/MyPerf4J
作者回复: 👍
共 2 条评论18 - Rain2019-08-04老师,为什么线程要sleep一下,看了注释还是不理解,求告知
作者回复: 正常情况下,如果一个线程set之后,该线程销毁了,然后key值由于弱引用刚好遇到一次GC,被回收了,此时value已经出现内存泄漏。而threadlocal为了解决这个问题,在后面的线程进行set时,会把之前key值为null的value清空掉,所以就不会出现大量内存泄漏了。 所以我们要模拟的就是,在后面进来的线程set之前,保证之前的线程还没有销毁,之前的key value就会保持,这样我们能模拟出大量value内存泄漏的情况出现。
共 3 条评论12 - CRann2019-07-31老师,刚看案例top命令后java的pid是1444,可是为什么后来查线程信息变成top -Hd 1593了?
作者回复: 截图截错了,自己操作的时候记得输入正确的pid就好了。
10 - 昨夜的柠檬2019-10-27实际项目中很多都是这样的,老师正确的写法应该是怎样的?
作者回复: 正确的写法是在set之后,记得在finally里面remove掉。 try{ localthread.set("test"); }finally{ localthread.remove("test"); }
9 - 殿小二2019-12-03老师 "而threadlocal为了解决这个问题,在后面的线程进行set时,会把之前key值为null的value清空掉,所以就不会出现大量内存泄漏了。" 后面的线程set的时候也只会在自己持有的ThreadLocalMap上进行操作吧,没有所谓的清空 key为null的value的值吧
作者回复: 是的,后面线程的set只是在当前线程的ThreadLocalMap上进行操作,不能清空其他线程ThreadLocalMap上已经泄漏的value值。这里指的是同一个线程,ThreadLocal实例没有外部强引用的情况下被回收了,此时key值会被回收,下一次在相同线程下set,value值会被清掉。
6 - 偏偏喜欢你2019-11-21老是您好最近看到项目有报内存溢出,发现是byte[]的问题,但是在Histogram 下看到排在第一位的是char[]数组,排第二的是byte[] 我是去排查char[]呢还是byte[]
作者回复: 这两个都是基础数据类型数组,例如char[]是String的基础数据类型,byte[]则是数据传输字节流的基础数据类型,排在第一二是比较常见的,我们需要再看看大小,如果异常大,那就是该基础数据类型之上的某个引用类型的问题。可以通过工具再展开树看看封装基础数据类型的引用类型是什么。
5 - Bruce2020-05-13问下老师,jmap和jstack命令能查历史的数据,譬如想查昨天的?
作者回复: 只能查看运行时的数据,如果需要历史数据,可以在JVM启动参数中加入dump日志参数,启动长时间JVM日志监控: 启动OOM监控日志:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof 启动GC日志:-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/tmp/heapTest.log
4 - Alex2020-01-29老师好,不好意思,想问一下,本门课程案例代码的git地址在哪里?我没有找到
作者回复: 由于代码比较少,这篇没有提交到github上,麻烦自己建个项目,拷贝下文章中的代码上去就好了。
3 - 星星滴蓝天2019-08-05代码中对jvm监控常用方法是啥?我翻了翻留言,没有人问这个问题的
作者回复: 可以通过ManagementFactory中的RuntimeMXBean实时获取JVM对应的值
4 - vvip2020-03-30老师,请问JVM上始终开启HeapDumpOnOutOfMemoryError这个参数,会影响性能吗?
作者回复: 有性能损耗
2 - 丁奇老师的粉丝2019-11-09老师您好,看了您的课程收货颇丰!谢谢 现在有个问题想咨询下 前提:jdk7u24 xms8g xmx8g g1垃圾回收 现象: 堆内存使用量从2G一直到6.3G都没有young gc 和 full gc 当堆内存使用量到了7G的时候直接进行了full gc 并且周期性重复上面的full gc 查看GC日志 eden区回收前高达6.3G 请问老师。现在该如何调优呢展开
作者回复: 如果没有设置年轻代与老年代的比例,默认分配给年轻代最大比例为60%,而且默认会先触发young gc,所以你说的这种情况比较少见,检查是否长时间存活的对象太多导致的。 这种情况优化设置参数已经没有很明显的作用了,建议先查找内存爆满的原因。
2 - null2021-04-29老师,请问一下,文章是二次修改过么?评论区有些关键字如:sleep,test0,test1。 我在文章只看到 test0 方法。另两个都没找到。 谢谢!1
- 静静聆听2020-12-10treadLocal会随着线程被回收而消失的,不会一直存在,极端情况才会内存泄漏共 1 条评论2
- Feng2019-08-31没看到有test1啊。。。
作者回复: 之前的代码已经优化了,所以去掉了test1,重写写了test0方法,两个方法对于大家来说不是很好理解
1 - WolvesLeader2019-08-21java -jar -Xms1000m -Xmx4000m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -Xms1g -Xmx1g -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/tmp/heapTest.log heapTest-0.0.1-SNAPSHOT.jar 配置了2个-Xms和-Xmx,为啥要配置2个
作者回复: 一个就够了,已修正
1 - 拒绝2019-07-18我用ab测试,设置请求数量一万,请求test0,内存就溢出,;还没请求到test1,?
作者回复: 内存泄露导致有大量对象无法回收,占满了堆内存情况下,就会导致内存溢出。我在这里加了一个test1只是为了创建更多的对象,从而更容易发生内存溢出。
1 - 恰饭哒2019-07-18老师太棒了,是我一直想总结而不知道怎么总结的一篇文章1