您的位置:首页 > 编程语言 > Java开发

Java垃圾回收

2015-09-05 16:46 218 查看
1. 垃圾回收

Java垃圾回收(GC)分为两个阶段:

  判定,判定哪些对象可以被回收,使用可达性分析算法;

  回收,回收那些无用的垃圾对象,常用的算法有:标记—清除算法、复制算法、标记—整理算法;

2. 可达性分析

当前的主流虚拟机都是使用可达性分析算法来判定一个对象是否还存活。

Java虚拟机中标记一系列称为GC Root的对象,可达性分析算法的基本思想即判断从这些GC Root对象到某个对象是否有引用路径,如果有则说明该对象仍然有用,否则即判定该对象是垃圾对象,可以被回收。

可以作为GC Root对象的有:

  (1)虚拟机栈中引用的对象(方法中的局部变量)

  (2)方法区中类的静态属性引用的对象

  (3)方法区中的常量引用的对象

  (4)本地方法栈中引用的对象(Native方法中的局部变量)

3. 标记算法

标记对象死亡(一定会回收该对象)的具体过程:

  (1)判定一个对象是否可达(使用可达性分析算法),如果不可达,将被标记为可回收;

  (2)然后进行第一次筛选,判断该对象是否需要执行finalize方法,如果该对象没有覆盖finalize方法或者已经执行过finalize方法,则不需要执行finalize方法,否则需要执行finalize方法;

  (3)如果不需要执行finalize方法,则直接判定对象死亡,否则将该对象加入一个F-Queue队列中,等待执行finalize方法;

  (4)然后进行第二次筛选,执行F-Queue队列中对象的finalize方法,如果finalize方法中对象被再次引用,则对象起死回生,将不被回收,否则,对象就将要被回收了;

4. 垃圾回收算法

虚拟机决定回收一个已经被标记为死亡的对象,就需要使用垃圾回收算法。常用的垃圾回收算法有:标记—清除算法、复制算法、标记—整理算法,其中,复制算法和标记—整理算法是对标记—清除算法的改进。

(1)标记—清除算法

  标记—清除算法是最基础最简单的算法,首先采用上面介绍的标记算法标记出死亡的对象,然后再统一回收所有被标记的对象的内存空间。

  


  其中蓝色表示存活着的对象,灰色表示尚未分配的内存,黄色表示待回收的内存。

  这个算法有较大的缺点,标记清除之后内存中会有大量的内存碎片。

(2)复制算法

  采用复制算法,将可用内存分为大小相同的两部分A和B,A用来给对象分配内存,B保留不用。当A没有足够的空间分配时,则将所有存活着的对象复制到B,然后清理A中的内存空间。

  


  复制算法的优点是清理内存的效率很高,也不会产生大量的内存碎片,但是一半的内存得不到利用,内存浪费实在太严重。

(3)标记—整理算法

  与标记—清除算法不同的是,标记出死亡对象后,不是直接就回收对象,而是将存活的对象都移动到一起,紧凑内存,然后清理剩余的内存空间。

  


(4)分代回收算法

  实际上,虚拟机中会将堆内存划分成新生代和老年代,对于新生代采用改进的复制算法进行内存回收,对于老年代采用标记—整理算法进行内存回收。

  


  

  在新生代中,将内存划分成三部分,一个Eden部分,两个Survivor(A和B)部分,HotSpot虚拟机中默认Eden和Survivor的大小比例是8:1。每次使用Eden部分和其中一个Survivor(A)部分,需要对这两个部分进行内存回收时,采用复制算法,将尚且存活的对象复制到另一个Survivor(B)中,然后清理之前的Eden部分和Survivor(A)部分。

  统计表明新生代内存中的对象存活时间通常较短,所以在进行内存回收时,存活的对象通常可以被容纳在另外一个Survivor(B)中。如果出现另一个Survivor(B)无法容纳全部存活的对象,先尽力复制到该Survivor(B)中,然后将剩余无法容纳的对象复制到老年代中。

5. 内存分配策略

对象优先在新生代的Eden区中分配内存,当Eden区的内存不够时将会发起一次GC;

大对象直接在老年代分配内存,例如:占用空间较多的数组通常就直接在老年代分配;

Eden区中的对象经过GC进入Survivor后,便有了年纪,初始值为1,以后每经过一次GC,年纪都会加1,直到某个设定的值时,这个对象就会被放进老年代中;

参考资料 《深入理解Java虚拟机》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: