《深入理解Java虚拟机》笔记之第3章 垃圾收集器与内存分配策略

 2019-12-22 11:02  阅读(821)
文章分类:JVM

1、判断对象是否存活的算法

(1)引用计数算法:对象中添加一个引用计数器,有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1。计数器的值为0的对象就是不可能再被使用的。(Python、微软的COM技术、Squirrel等使用此算法进行内存管理)。缺点在于难以解决对象之间的相互循环引用问题。

(2)根搜索算法:从一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。(Java、C#、Lisp等使用此算法)

2、回收方法区(即HopSpot虚拟机中的永久代)

堆中(尤其是新生代中),常规应用进行一次垃圾收集一般可以回收70%~95%的空间,而永久代的垃圾收集效率远低于此。

永久代的垃圾收集主要加收两部分的内容:废弃常量和无用的类。

3、垃圾收集算法

(1)标记–清除(Mark-Sweep)算法;

(2) 复制(Copying)算法:将内存要为大小相等的两块,每次只使用其中的一块,当这一块内存完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉(现代商业虚拟机都采用这种方式来回收新生代)。

新生代中的对象有98%是朝生夕死的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor。当回收时,将Eden和Survivor中存活着的对象一次性地拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor的空间(Hotspot虚拟机默认Eden和Survivor的比例为8:1)。

(3)标记–整理(Mark-Compact)算法:一般老年代采用。

一般而言,老年代GC(Major GC/Full GC)比新生代GC(Minor GC)的速度慢10倍以上。

4、内存分配与回收策略

(1)对象优先在Eden分配。如果Eden区没有足够的空间,虚拟机将发起一次Minor GC;

(2)大对象直接进入老年代。大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组。因此,写程序时应该“朝生夕死”的“短命大对象”。

(3)长期存活的对象将进入老年代。对象在Eden出生,熬过一次Minor GC,其对象年龄就加1,默认对象年龄为15时,就会晋升到老年代。

(4)动态年龄判定。如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

(5)空间分配担保。Minor GC前,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小。如果大于,则改为直接进行一次Full GC;如果小于,则查看HandlePromotionFailure设置是否允许担保失败;如果允许,那只会进行Minor GC;如果不允许,则也要改为进行一次Full GC。

点赞(1)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 《深入理解Java虚拟机》笔记之第3章 垃圾收集器与内存分配策略

相关推荐