java垃圾收集方法

来源:互联网 发布:windows下dmg转换cdr 编辑:程序博客网 时间:2024/06/05 17:20

Java内存区域中,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭。这几个区域内存分配和回收都具有确定性,在这几个区域内不需要考虑太多的回收问题。Java堆和方法区(常量池是方法区的一部分)则不一样。一个接口中的多个实现类需要的内存可能不一样,一个方法中大多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分的内存。


引用计数法

给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,;当引用失败时,计数器值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。

Java中并没有使用选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间的相互循环引用问题。


根搜索算法

Java使用的根搜索算法判定对象是否存活。这个算法的基本思路就是通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径被称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象时不可用的。

Java中可作为GC Roots的对象包括下面几种:

虚拟机栈中的引用对象。

方法区中的类静态属性引用的对象。

方法区中的常量引用的对象。

本地方法栈中的native的引用的对象。


垃圾收集算法

标记-清除算法

如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的算法。

缺点:主要有两个,一个是效率问题,标记和清除过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片。

复制算法

它将可用内存按容量划分为大小相等的相等的两块每次都只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块上,然后再把已使用过的空间一次清理掉。

这样就不用考虑内存碎片等复杂情况,简单高效。不过内存缩小为原来的一半,代价太高。

现在商业虚拟机都采用这种收集算法来回收新生代,IBM的专门研究表明,新生代中的对象98%是朝生夕死的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor中还存活着的对象一次性地拷贝到另一个Survivor空间上,最后清理掉Eden和刚才用过的Survivor的空间。HotSpot虚拟机默认Eden和Survivor大小比例为8:1(-XX:SurvivorRatio=8)。也就是每次新生代中可用内存空间为整个新生代容量的90%,只有10%会被浪费。我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其它内存(这里指老年代)进行分配担保。

标记-整理法

标记过程与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动。然后直接清理掉边界以外的内存。

分代收集算法

当前商业虚拟机的垃圾收集器大都采用了“分代收集”算法,这种算法并没有什么新的思想,只是根据对象的存活周期的不同将内存化为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现大批对象死去,只有少量存活,那就选用复制算法。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。


内存分配与回收策略

对象优先在Eden分配

大对象直接进入老年代

所谓大对象就是指需要大量连续内存空间的Java对象,最典型的是那种很长的字符串及数组。可以通过-XX:PretenureSizeThreshould参数,令大于这个设置值的对象直接在老年代分配。

长期存活的对象将进入老年代

虚拟机给没个对象定义一个对象年龄计数器,每经历过一次GC 年龄就加1,当它年龄增加到一定程度(默认是15)时,就晋升到老年代中。可以通过-XX:MaxTenuringThreshold来设置。

动态对象年龄判断

为了更好的适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

空间分配担保

在发生Minor GC时,虚拟机会检测之前每次普及到老年代的平均大小是否大于老年代剩余空间大小,如果大于,则改为直接进行一次Full GC。如果小于,则查看HandlePromotionFailture设置是否允许担保失败;如果允许,那只会进行Minor GC;如果不允许,则也要改为进行一次Full GC。


0 0
原创粉丝点击