标签:
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的想出来。
一、判断对象是否已经死了
1.应用计数算法
给每个对象添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1,当应用失效的时候就减1,任何时刻计数器为0的时候表示对象就是不可用状态。
但是Java虚拟机并没有选择这种算法,原因是很难解决对象之间相互引用的问题。
2.可达性分析算法
通过一系列的称为“GC Root”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有任何引用链相连接的时候,证明这个对象是不可用的。
在Java语言中,作为GC Root的对象有如下
①虚拟机栈中引用的对象。
②方法区中类静态属性引用的对象。
③方法区中常量引用的对象。
④本地方法栈中JNI(Native方法)应用的对象。
二、垃圾收集算法
1.标记—清除算法
“标记”:首先标记出所有需要回收的对象。
“清除”:标记完成后统一回收被标记的对象。
不足之处:① 效率问题,标记和清理两个过程效率都不高。②标记清理之后会产生大量不连续的内存碎片。
2.复制算法
将内存分成两个大小相等的两块,每次只使用一块,当这一块内存用完了,就将还存活的对象复制到另一块上,然后把已经使用过的内存空间一次清理掉。
好处:回收是一次性回收,也不用考虑内存碎片等复杂情况。只需要移动堆顶的指针,实现简单,效率高。
坏处:浪费一般内存。
现在商业虚拟机使用的这种算法回收新生代:将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收的时候,将Eden区和Survivor区中还存活的对象一次性的复制到另一块survivor空间上,最后清理Eden区和刚才使用的survivor区。HotSpot默认Eden与Survivor比例是8:1.,所以只有10%空间浪费。当Survivor空间不够用时,需要依赖其他内存(老年代)进行分配担当。
3.标记—整理算法
复制算法在对象存活率比较高的时候会进行比较多的复制操作,效率会变低,所以老年代不适合这种算法。
4.分带收集算法
根据对象活跃周期不同将内存划分为几块:一般把Java堆分为新生代和老生代。
新生代:一般使用复制算法。
老生代:一般使用“标记—清理算法”或者“标记—整理算法”。
三、HotSpot的算法实现
1. 枚举根节点
当进行垃圾回收前的对象可达性分析时,对执行时间的敏感体现在GC停顿上。因为这项分析工作必须在一个能保证一致性的快照中进行——整个分析过程中所有执行都停在某个时间点上。GC停顿是性能瓶颈的重要原因。
使用OoMap实现快速节点枚举。
2.安全点(Safepoint)
并不是每个指令都会创建OoMap,我们会为特定的指令或者说程序特定的位置创建OoMap,例如:方法调用、循环跳转、异常跳转等。
如何将所有线程都跑到安全点停顿:①抢先式中断,在GC发生时,首先把所有线程全部中断,如果发现不在安全点上则恢复线程叫它跑到安全点再停止。
3.安全区域
安全区域表示一段代码,不会引起引用变化。
四、垃圾收集器
标签:
原文地址:http://www.cnblogs.com/zhangzongxing01/p/5537856.html