参考原文:https://www.zhihu.com/question/427461208/answer/2537026920
jinfo
可以打印一些当前jvm的各种参数,比如jvm的一些启动参数,jvm中的一些属性k-v等,可以通过 jinfo --help查看具体的命令。
jmap(内存溢出解决方案)
这个参数可以查看JVM内存的一些相关数据;
通过jps获取java进程的PID,通过jmap分析当前java进程的内存数据,常用命令:
- 1.堆历史:
jmap -histo[:live] <pid> [ > ./xx.log]
: 可以看到当前JVM中所有已加载内的类创建对象的数量,占用内存等,可以导入文件中查看; - 2.堆信息:
jmap -heap <pid>
:可以查看java程序新生代和老年代的占比即使用情况。 - 3.堆dump
jmap -dump:format=b,file=xx.hprof <pid>
: 可以dump堆日志,看到的和jmap类似,可以使用visualVM查看。
通过jmap可以查看堆的使用情况,比如定位简单的内存泄漏,通过1,3可以看到那些类的对象比较多。
可以设置参数控制发生内存溢出时记录xx.hprof日志,此可以用于分析内存泄漏。-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=xxx/xxx/xx.hprof
jstack(cpu占用高解决方案)
这个命令可以查看线程的堆栈信息,jstack可以定位到简单的死锁,常用的是通过jstack定位CPU高的问题,具体步骤是:
- 1.
top
命令查看当前占用cpu最高的进程pid; - 2.
top -p <pid>
查看占用内存高的cpu的进程,按 H 来获取当前进程中占用cpu最高的线程的tid; - 3.
jstack <pid> | grep -A10 <16进制tid>
查看占用线程最高的线程正在执行的具体类信息。注意:tid的16进制要小写。
通过这个流程可以直接定位到哪个线程正在执行占用了大量的cpu,包括执行哪个类,非常方便,这个面试经常问。
jstat(FullGC频繁解决方案)
这个命令可以查看堆的各个部分的详细的使用情况,可以通过jstat --help查看帮助;
最常用的命令jstat -gc <pid> [1000 10]
表示查看gc情况,每1秒打印一次总共打印10次(可选),可以查看各个带的使用总大小和使用大小,关键还可以看youngGC,和FullGC各自总次数,总耗时以及一起的耗时等,对于jvm的优化就是要去优化它的FullGC次数,FullGC越少越好,最好控制在FullGC几个小时甚至几天一次,具体看业务的情况。
FullGC频繁分析流程:
FullGC的频繁发生我们不能直接去猜为什么,需要通过一定的分析,去判断是什么原因导致的,一般我们需要用到上面的命令定时去观察堆的情况。
- 1.观察Eden区的对象增长,如每秒有多少对象创建;
- 2.发生youngGC的间隔时间及每次的耗时,每次youngGC有多少对象进入新生代有多少进入老年代;
- 3.触发fullGC的间隔时间和耗时,每次FullGC会释放多少空间。
构建模型:
系统所有线程每秒会产生多少M的对象 ==> ①进入Eden;②大对象进入老年代? ==> n秒占满Eden区 ==> 进行youngGC ==> ①进入老年代对象个数(产生原因,动态年龄判断机制?已达到年龄阈值?) ==> FullGC后剩余对象个数
分析问题:
触发FullGC的原因是老年代装不下了,所以需要看老年代为什会频繁的放入对象。。。
- 1.给JVM分配的堆内存太小,无法满足要求,老年代每次GC后都只能释放少量空间,可以增加堆的大小。
- 2.大对象设定阈值太小,可能系统中某个产生了临时的大对象,如一次加载了好多数据到内存,可以修改阈值但最好优化代码。
- 3.动态年龄的判断机制导致过多的对象进入老年代,如果判断业务大量对象都是朝生夕死可以适当调大新生代与老年代的比例,避免动态年龄判断导致许多垃圾对象进入老年代。
- 4.老年代的空间担保机制可能会导致每次youngerGC前都要进行FullGC,是否开启了空间担保机制,如果没有开启同时每次有大量对象生成则会导致每一次或者几次youngGC都要进行FullGC