九、JVM监测工具
jps: 查看Java进程 (java命令)
jstat:只能查看当前时刻的内存情况;可以查看到 新生代、老年代中的内存使用情况
jmap:查看堆内存的占用情况;也可以执行dump操作
jconsole:图形的监控界面
例如:如果通过jconsole中的"执行gc"按钮发现 GC回收的内存太少,就说明当前进程是存在问题的(至少是可以被优化的)
jvisualvm: 监视 - 堆Dump -查找最大对象,从中可以发现 当前进程中是哪个对象 占据了最大的内存,从而对这个对象进行分析。
通过VM参数实现: 当内存溢出时,自动将溢出时刻的内存dump下来。
-Xmx100m
-Xms100m
-XX:+HeapDumpOnOutOfMemoryError
十、GC调优
Java开发者为什么不把所有的参数调到最优?非得让我们手工去调?
取舍。
调优实际是是一种取舍,以xx换xx的策略。因此在调优之前,必须明确方向:低延迟?高吞吐量呢?
有两种情况需要考虑:
1.在已知条件相同的前提下, 牺牲低延迟 来换取 高吞吐量,或者反之。
2.随着软件硬件技术的发展,可能 二者都升高。
GC的发展:
JVM自身在GC上进行了很多次的改进升级:
JVM默认的GC: CMS GC(在jdk9以后被逐步废弃) -> G1 GC(jdk9) -> Z GC(jdk11)
-
Serial GC:
串行GC,是一种在单核环境下的串行回收器。当GC回收的时刻,其他线程必须等待。一般不会使用。
-
Parallel GC:
在Serial 的基础上,使用 了多线程技术。 提高吞吐量。
-
CMS GC
CMS使用了多线程技术,使用“标记-清除”算法,可以极大提升效率 (尤其在低延迟上有很大的提升)。繁琐,参数太多,对开发者的经验要求太高。
-
G1 GC
jdk9开始使用的默认GC。特点:将堆内存划分为很多大小相等region,并会对这些区域的使用状态进行标记。以便GC在回收时,能够快速的定位出哪些region是空闲的,哪些是有垃圾对象,从而提升GC的效率。G1使用的算法是“标记-整理”算法。
-
Z GC
jdk11开始提供全新的GC。回收TB级别的垃圾 在毫秒范围。
如果从生命周期角度划分,GC也可以划分成:Minor GC,和Full GC
- Minor GC:回收新生代中的对象
- Full GC:回收整个堆空间(新生代、老年代)
案例:
如果通过监测工具发现: Minor GC和Full GC都在频繁的回收,如何优化?
Minor GC为什么会频繁执行?因为 新生代中的对象太多了 Minor GC->短生命周期的对象太多了->造成逃逸到老年代中的对象越多-> 新生代多+老年代多->Full GC
Minor GC:可以尝试调大 新生代的最大空间
再调大 新生代晋升到老年代的阈值,从而降低 短生命周期的对象 从新生代转移到老年代的概率。