Java虚拟机详解----JVM常见问题总结 (6)

89af7bbc-5331-4c62-ab7e-18e93350f826

上图中,初始标记和重新标记时,需要stop the world。整个过程中耗时最长的是并发标记和并发清除,这两个过程都可以和用户线程一起工作。

 

优点:

  并发收集,低停顿

缺点:

(1)导致用户的执行速度降低。

(2)无法处理浮动垃圾。因为它采用的是标记-清除算法。有可能有些垃圾在标记之后,需要等到下一次GC才会被回收。如果CMS运行期间无法满足程序需要,那么就会临时启用Serial Old收集器来重新进行老年代的手机。

(3)由于采用的是标记-清除算法,那么就会产生大量的碎片。往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次full GC

疑问:既然标记-清除算法会造成内存空间的碎片化,CMS收集器为什么使用标记清除算法而不是使用标记整理算法:

答案:

  CMS收集器更加关注停顿,它在做GC的时候是和用户线程一起工作的(并发执行),如果使用标记整理算法的话,那么在清理的时候就会去移动可用对象的内存空间,那么应用程序的线程就很有可能找不到应用对象在哪里

七、Java堆内存划分:

根据对象的存活率(年龄),Java对内存划分为3种:新生代、老年代、永久代:

1、新生代:

比如我们在方法中去new一个对象,那这方法调用完毕后,对象就会被回收,这就是一个典型的新生代对象。 

现在的商业虚拟机都采用这种收集算法来回收新生代,新生代中的对象98%都是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的空间会被浪费。

当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖于老年代进行分配担保,所以大对象直接进入老年代。同时,长期存活的对象将进入老年代虚拟机给每个对象定义一个年龄计数器)。

来看下面这张图:

ef34e1c5-c6e1-4108-a939-87c9f5de0fff

Minor GC和Full GC:

GC分为两种:Minor GC和Full GC

Minor GC:

  Minor GC是发生在新生代中的垃圾收集动作,采用的是复制算法。

对象在Eden和From区出生后,在经过一次Minor GC后,如果对象还存活,并且能够被to区所容纳,那么在使用复制算法时这些存活对象就会被复制到to区域,然后清理掉Eden区和from区,并将这些对象的年龄设置为1,以后对象在Survivor区每熬过一次Minor GC,就将对象的年龄+1,当对象的年龄达到某个值时(默认是15岁,可以通过参数 --XX:MaxTenuringThreshold设置),这些对象就会成为老年代。

但这也是不一定的,对于一些较大的对象(即需要分配一块较大的连续内存空间)则是直接进入老年代

Full GC:

  Full GC是发生在老年代的垃圾收集动作,采用的是标记-清除/整理算法。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjwyz.html