查看 gc 状态
jstat -gc pid
dump 内存
/opt/taobao/java/bin/jmap -dump:file=/tmp/1.bin,format=b pid
如果报:Unable to open socket file: target process not responding or HotSpot VM not loaded
则在前面加:sudo -u USERID (即进程的用户名)
如:
sudo -u admin /opt/taobao/java/bin/jmap -dump:format=b,file=/tmp/%s/%s.bin %s
mac 上:
jmap -dump:format=b,file=/Users/shicai.xsc/Downloads/bin/10.bin 44005
MAT
- 安装
如果碰到内存不够问题,参考
https://stackoverflow.com/questions/47909239/how-to-run-eclipse-memory-analyzer-on-mac-os
- 使用
这几篇文章讲得不错:
https://eclipsesource.com/blogs/2013/01/21/10-tips-for-using-the-eclipse-memory-analyzer/ https://www.jianshu.com/p/759e02c1feee
- 查询某个类在内存中所有实例
select * from com.alibaba.cobar.net.handler.FrontendAuthenticator
- shallow heap 和 retained heap 区别
https://blog.csdn.net/a740169405/article/details/53610689
换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。
- 用少内存来分析很大的 heap 文件
https://www.techpaste.com/2015/07/how-to-analyse-large-heap-dumps/
主要是给 MAT 的 MemoryAnalyzer.ini (Applications/mat%202.app/Contents/Eclipse/ 内)加上下面配置
-Xms6144m
-Xmx8192m
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:+CMSClassUnloadingEnabled
-XX:+UseCMSInitiatingOccupancyOnly
- 通过 dominator_tree 找到最耗内存的线程
- 通过 thread_overview 找到线程调用栈,找出其中哪一个步骤耗费内存最多,以及当时的栈数据
jstack,定位死循环、线程阻塞、死锁等问题
一般查找 waiting to lock / waiting on < ,看看哪些线程在等锁。然后拿相应的锁去搜,看哪些线程持有这个锁。
比如这个是死锁:
perf top
关于 perf 的更多介绍 https://blog.csdn.net/u014608280/article/details/80265718
在 linux 上像 top 命令一样可以看到函数级 cpu 消耗
sudo perf top
async-profiler
github 地址:git clone https://github.com/jvm-profiling-tools/async-profiler
参考:https://www.jianshu.com/p/9364028cca4e
~/async-profiler/profiler.sh -d $interval -f /tmp/profiler-$time.svg $pid
生成 /tmp/profiler-2019-11-11-1111.svg 这个文件
下载到本地通过浏览器打开,可以通过火焰图看到 cpu 瓶颈在何处。
除了以上功能外,async-profiler 还可以快速找到代码里的锁瓶颈,锁可能会导致 CPU 利用率低。
~/async-profiler/profiler.sh -e lock -d 5 $pid
perf record + FlameGraph
利用 linux 自带的 perf + 开源的 FlameGraph,总体效果和 async-profiler 差不多
perf record 采集事件指标数据,并汇总到perf.data
perf record -e $event -F $freq -p $pid -g -- sleep $seconds
参数解析:
-e: 采集事件, 默认为cpu-cycles
-F: 采集频率
-p: 进程ID
-g: 记录函数调用关系(CALL-GRAPH)
sleep 采集时间秒数, 不设定默认等到Ctrl-c结束为止。
FlameGraph
https://github.com/brendangregg/FlameGraph?spm=ata.13261165.0.0.5c592745IrDwUq&file=FlameGraph.git
其他阅读
- jprofiler
https://www.cnblogs.com/jpfss/p/8488111.html
- JDK 内置命令
https://blog.csdn.net/fenglibing/article/details/6411940
- 计算 java 对象所占内存大小
https://www.jianshu.com/p/9d729c9c94c4
- 为什么 dump 出的内存远小于在使用的
- shallow heap 和 retained heap 区别
https://blog.csdn.net/a740169405/article/details/53610689 换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。 不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。
- jvm 各参数意义
https://www.cnblogs.com/marcotan/p/4256885.html
- jstack,定位死循环、线程阻塞、死锁等问题
https://www.cnblogs.com/chenpi/p/5377445.html
https://www.techpaste.com/2013/11/steps-find-locking-issues-jstack/ jstack 找死锁https://www.cnblogs.com/zhengyun_ustc/archive/2013/03/18/tda.html
https://my.oschina.net/robinyao/blog/807450 写出 jvm 检查不到的死锁 - GC 日志详解
https://blog.csdn.net/renfufei/article/details/49230943
https://blogs.oracle.com/poonam/understanding-cms-gc-logs CMS GC 日志详解
https://blog.csdn.net/caomiao2006/article/details/47780765 jstat -gc 和 gc.log 中关于 Full GC 的数目不一致https://blog.csdn.net/hellozhxy/article/details/80649342 聊聊JVM(四)深入理解Major GC, Full GC, CMS
https://segmentfault.com/a/1190000015182001 CMS垃圾回收和线上Full GC排查
1. Full GC == Major GC指的是对老年代/永久代的stop the world的GC
2. Full GC的次数 = 老年代GC时 stop the world的次数
3. Full GC的时间 = 老年代GC时 stop the world的总时间
4. CMS 不等于Full GC,我们可以看到CMS分为多个阶段,只有stop the world的阶段被计算到了Full GC的次数和时间,而和业务线程并发的GC的次数和时间则不被认为是Full GC
5. Full GC本身不会先进行Minor GC,我们可以配置,让Full GC之前先进行一次Minor GC,因为老年代很多对象都会引用到新生代的对象,先进行一次Minor GC可以提高老年代GC的速度。比如老年代使用CMS时,设置CMSScavengeBeforeRemark优化,让CMS remark之前先进行一次Minor GC。