JVM性能优化(一)之了解jvm分区
1、首先打开jvisualvm.exe,安装插件visualgc插件,重新打开jvisualvm.exe,

Metaspace就是方法区
old老年代
eden新生代
s0s1 survivor区
2、为何这么设计?
假设不做分区,那么所有的对象都在一个区中,

如果现在有些对象需要回收,那么如下图

橙色为回收对象,那么回收结束后,整个空间变得碎片化,这样就会导致有些大对象无法分配到空间,但是实际上是有很多剩余空间的!
那么此时,就会触发垃圾收集,这种情况就会导致频繁的垃圾收集,导致cpu被垃圾收集大量占用!
所以,我们期望的情况是:垃圾收集越少越好,cpu可以更多的分配给业务代码!
3、所以解决方案来了!

1)如上图,把整个堆空间划分为两个区域,老年代和新生代,这样gc就不用扫描整个堆空间了,效率有所提升!但是仍然没有解决碎片问题。

2)如上图,所以在进行一次GC时,假设橙色部分可以被回收掉,则直接回收,发现蓝色部分不能回收,则age变为1,同时被复制到survivor区。如下图:

这样就可以在eden区获得了连续的空间,虽然牺牲了一部分空间大小,但是解决了空间碎片问题。
那么这里还有一个问题,就是Eden区大还是Survivor区大?大部分对象都是可以被一次回收的,只有少部分对象可以存活,所以Eden区应该大一些。
3)在这之后,我们又创建对象,分配到eden区,Eden区又满了,又发生了一次youngGc,这时对Eden区和survivor同时进行回收,如下图:

橙色的对象被回收,Eden区的对象又要被复制到Survivor区,但是这时Survivor区却存在碎片化的问题了,所以解决方案如下图:

将Survivor区分成两个空间,发生youngGc时,Eden内的碎片数据复制到S1,将S0内的碎片数据也复制到S1,这样S0的空间就连续了!如下图所示:

然后对象再分配再回收时,S0与S1内的对象就来回被复制,总是有一个S区是空的,这就可以保证空间的连续性,但是也是牺牲了一部分空间!
4)S区的对象age不断在增加,当age>15时,被移动到old区。如果S区空间不够了,会从old区借一部分空间。如果old区空间也不够了,会触发OldGc,如果old区也没有空间了,那就会OOM异常。如果有一个超大对象,Eden区分配不下,会直接分配到Old区。

浙公网安备 33010602011771号