你好 我是懂java的测试
前言
前两篇文章介绍了一些jvm的理论知识,反响还不错,本篇文章分享一些jvm比较高阶的知识。
还是老规矩,本文将以问答形式,由易到难,循序渐进讲述jvm相关的知识。不拽那些官方晦涩难懂的词语,只想用白话通俗的语言,力争让大家都能看懂jvm。
1、GC日志怎么看?
上篇文章最后显示的是GC日志
Java HotSpot(TM) 64-Bit Server VM (25.211-b12) for windows-amd64 JRE (1.
8.0_211-b12), built on Apr 1 2019 20:53:26 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 8133460k(1586644k free), swap 33299284k(15627288k free)
CommandLine flags: -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=5242880 -XX:NewSize=5242880 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
0.804: [GC (Allocation Failure) [PSYoungGen: 3984K->504K(4608K)] 3984K->2094K(9728K), 0.0034707 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 4608K, used 3727K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
eden space 4096K, 78% used [0x00000000ffb00000,0x00000000ffe25c98,0x00000000fff00000)
from space 512K, 98% used [0x00000000fff00000,0x00000000fff7e010,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 5120K, used 3638K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
object space 5120K, 71% used [0x00000000ff600000,0x00000000ff98db10,0x00000000ffb00000)
Metaspace used 3177K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 347K, capacity 388K, committed 512K, reserved 1048576K
CommandLine flags: -XX:InitialHeapSize=10485760。。。这个是本次运行所使用的默认的Jvm配置,
[GC (Allocation Failure) 意味着新生代,没有多余的空间放置最新的对象,所以会导致youngGc,
PSYoungGen:是使用-XX:+UseParallelOldGC(新生代,老年代都使用并行回收收集器
3984K->504K(4608K) 这个是整个新生代内存状况,新生代有4608K内存容量,回收前已经有3984K了,回收后还剩504K,
3984K->2094K(9728K) 这个是整个堆内存回收状况,堆内存有9728K,gc前使用了3984K,gc后堆内存使用了2094K,
0.0034707 secs,本次gc消耗的时间,因为是youngGc所以时间特别短。
[GC PSYoungGen total 4608K, used 3727K 年轻代总共有4608K,目前使用了3727K,
eden space 4096K, 78% used ,eden区有4096K,78%已经被使用,
from space 512K, 98% used ,from 区有512K,98%已经被使用,
to space 512K, 0% used, eden区有512K,0%已经被使用,
还有ParOldGen(老年代)、Metaspace(元空间) 区域,和上面解读一致,不做赘述。
2、知道哪些jvm相关的命令吗?
jstat
jstat命令可以让你看到堆内存区域分配情况,gc的次数和耗时,通过连续输出的形式,可以看到gc的频率和各个区域的容量分布,有利于摸清当前jvm运行的情况。
常见的命令jstat -gc pid 1000 40 其中pid是java进程的id,执行jps命令可获取,整个命令的含义是打印java的gc信息 每隔1000ms 打印40次。
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
GCT:垃圾回收消耗总时间
YGC: Young GC 代表Minor GC次数;
YGCT: Young GC Time 代表Minor GC耗时;
FGC: Full GC 代表Full GC次数;
FGCT:老年代垃圾回收消耗时间;
GCT: GC Time 代表Minor & Full GC共计耗时;
jmap
如果只要简单的看看jvm频率,进行调优,其实jstat命令就已经足够了,
但是如果发现新生代对象新增很快,然后就想看看究竟什么对象创建这么快,可以使用Jmap 命令 。
jmap -heap pid
获取heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况。
jmap -dump:live,format=b,file=myjmapfile.txt 进程id
查看堆内存快照,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件
jmap -histo pid
命令会打印出以下信息,可以看到究竟哪个对象占用空间最多
还有其他命令 ,jhat、jps、jinfo等,限于篇幅限制,可自行探索。
3、怎么去定位youngGc问题?
本地项目中模拟使用,可复制以下配置到idea中
-XX:NewSize=104857600 -XX:MaxNewSize=104857600
-XX:InitialHeapSize=209715200 -XX:MaxHeapSize=209715200 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:PretenureSizeThreshold=3145728 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log
堆内存设置成200MB,年轻代设置了100MB,Eden区80MB,老年代是100MB,
Idea中项目代码如截图所示
执行jps命令 获取 java进程,java进程号是11744
执行jstat -gc pid 11744 1000 1000,执行结果如下
怎么去分析呢?
单看EU那列,最少也就3M左右空间,之后每秒都会有5M对象新增,eden区域总共才81M左右,直到78M左右,再次增加5M的对象,jvm发现eden放不下了,只能YoungGc,回收大部分对象,回收完,Eden区域就突然下降到1M左右,YGC增加了一次,FGC次数不变,说明只发生了一次YoungGc,YGCT将近0.044秒。
再往下看,15秒左右就会进行一次YoungGc,每次耗时就45毫秒,相对比较频繁,但是耗时45ms勉强可以接受,可不做调优。
4、怎么去定位FullGc问题?
还是上面的jvm配置,只是代码稍微修改下
执行jstat
如截图所示,Fgc次最高每秒100多次,虽然每次FGCT时间比较短,但是因为这是模拟创建新增对象,看不出很大影响。
5、JVM调优的原则或步骤是什么?
如果是新系统,首先大家应该估算一下自己参与的系统每个核心接口每秒多少次请求,每次请求会创建多少个对象,每个对象大概多大,每秒钟会使用多少内存空间?这样接着就可以估算出来Eden区大概多长时间会占满?然后就可以估算出来多长时间会发生一次Young GC,而且可以估算一下发生You ng GC的时候,会有多少对象存活下来,会有多少对象升入老年代里,老年代对象增长的速率大概是多少,多久之后会触发一次Full GC,通过一连串的估算,就可以合理的分配年轻代和老年代的空间,还有Eden和Survivor的空间。
如果是已经线上运行的项目,可以使用使用jvm的相关命令,查看jvmgc频率和每秒新增的对象大小。
原则就是:尽可能让每次Young GC后存活对象远远小于Survivor区域,避免对象频繁进入老年代触发Full GC。
最理想的状态下,就是系统几乎不发生Full GC,老年代应该就是稳定占用一定的空间,就是那些长期存活的对象在躲过15次Young
GC后升入老年代自然占用的。然后平时主要就是几分钟发生一次Young GC,耗时几毫秒。
总结
至此三篇关于Jvm的分享就结束了,jvm是java的底层技术,在性能调优和面试中占据着重要地位,建议大家看完这三篇文章之后再去搜寻其他学习资料,这样才能在面试中游刃有余,在面试中技术深度这块满分通过。
加我微信,免费面试辅导、学习资料、简历模板获取、加入学习群。