Java虚拟机(三):垃圾收集方式-分代,复制,标记整理算法

来源:互联网 发布:网络搞笑歌曲你是谁 编辑:程序博客网 时间:2024/05/15 23:50

Java虚拟机(三):垃圾收集方式-分代,复制,标记整理算法

http://blog.csdn.net/pzxwhc/article/details/39184357

对于垃圾收集,解决3个问题:

一.哪部分内存需要回收

二.什么时候进行内存回收

三.如何回收内存

四.GC日志分析


对于一.哪部分内存需要回收

首先我们知道JVM的内存结构分为5大块,分别是程序计数器,JVM方法栈,本地方法栈,JVM方法区,JVM堆。其中程序计数器,JVM方法栈,本地方法栈是和线程共存亡的,不需要我们考虑内存回收问题,所以在JVM中,最需要考虑的内存回收部分是JVM方法区和JVM堆。

对于二.什么时候进行内存回收

当对象死去的时候进行内存回收,那么如何判断一个对象是否已经死去,主要通过可达性分析算法。Java中并未采用引用计数法,因为引用计数法无法解决循环引用的问题。对于可达性分析方法:它是通过一系列称为“GC Roots”的对象作为起始点,当一个对象到GC Root没有任何引用链相接的时候,则证明这个对象不可用,即可以进行回收。

如图:

那么这个时候obj5,obj6,obj7就会被认定为回收的对象。

Ps:这个Gc Roots是什么东西:1.虚拟机栈(栈帧中的本地变量表)2.方法区中类静态属性引用的对象 3.方法区中常量引用的对象 4.native方法引用的对象。

对于三.如何回收内存

三种方法:1.标记-清除法。2.复制算法。3.标记-整理法。4.分代收集法

对于1.标记-清除法:

就是先标记哪些对象实例不用,然后直接清除。缺点就是产生大量的内存碎片,下次若要存储一个大的对象,无法找到连续内存而又必须提前GC。

对于2.复制算法:

即把内存分成相等的AB两块,每次只使用其中的一块。比如当A内存使用完后,就把A中还存活着的对象复制到另外一块内存中去(B),然后再把已经使用过的内存清理掉。优点:这样就不用考虑内存碎片的问题了。缺点:内存减半,代价略高。

实际应用中不会以1:1的比例划分两块,比如JVM堆内存又分为新生代,老生代。那么在新生代中,又分为一块较大的Eden空间和两块较小的Survivor空间,例如HotSpot默认为8:1:1的比例。每次使用Eden区域和其中一块Survivor区域。当回收的时候,就把这两个区域存活的实例复制到另外一个Survivor区域中。(若不够大,则需要老年代进行分配担保)。Ps:具体有关内存分配看另一篇博文。

对于3:标记-整理法:

复制算法当存活的实例多的时候,就需要大量复制,效率不高,不适合老生代这种。那么就可以采用标记-整理算法。也就是先标记,然后对存活的对象进行移动,全部移动到一端,然后再对其它的内存进行清理。

对于4:分代收集法:

目前普遍采用的就是分代收集法。就是说把JVM堆内存有细分成很多部分(如新生代,老生代,永生代),不同部分采用不同的算法,这样来提高效率。


对于四.GC日志分析


Full GC 信息与 Minor GC 的信息是相似的,这里就不一个一个的画出来了。
从 Full GC 信息可知,新生代可用的内存大小约为 18M,则新生代实际分配得到的内存空间约为 20M(为什么是 20M? 请继续看下面…)。老年代分得的内存大小约为 42M,堆的可用内存的大小约为 60M。可以计算出: 18432K ( 新生代可用空间 ) + 42112K ( 老年代空间 ) = 60544K ( 堆的可用空间 )
新生代约占堆大小的 1/3,老年代约占堆大小的 2/3。也可以看出,GC 对新生代的回收比较乐观,而对老年代以及方法区的回收并不明显或者说不及新生代。
并且在这里 Full GC 耗时是 Minor GC 的 22.89 倍。


0 0
原创粉丝点击