Java 垃圾收集器 ---(摘抄,算是笔记)

来源:互联网 发布:u盘安装linux卡在scsi 编辑:程序博客网 时间:2024/06/05 19:57

GC原理

    Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放。
    对于程序员来说,分配对象使用new关键字;释放对象时,只要将对象所有引用赋值为null,让程序不能够再访问到这个对象,我们称该对象为"不可达的".GC将负责回收所有"不可达"对象的内存空间。
    对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用可达性分析算法确定哪些对象是"可达的",哪些对象是"不可达的".当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。但是,为了保证GC能够在不同平台实现的问题,Java规范对GC的很多行为都没有进行严格的规定。例如,对于采用什么类型的回收算法、什么时候进行回收等重要问题都没有明确的规定。因此,不同的JVM的实现者往往有不同的实现算法。

    

1、引用计数法

给对象添加一个引用计数器,每当有地方引用它,计数器 +1;每当一个引用此对象的引用失效,计数器 -1 ;任何计数器值等于 0 时,这个对象就不能在被使用。这种方法实现简单,判定效率也很高,但是难以解决对象之间相互循环引用的问题


2、可达性分析法

主流的程序语言(Java 、C#,Lisp)使用时可达性分析法来判定对象是否存活的。算法的基本思路是:通过一系列的“GC Roots”对象作为起点,从这些起点开始向下搜索,搜索到所走过的路径成为“引用链(Reference Chain)”当前一个对象到GC Roots没有任何引用链相连(就是图论中说的对象不可达时),说明此对象不可用。




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

1、虚拟机栈(栈中的本地变量表)中引用的对象

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

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

4、本地方法栈中JNI(即一般说的Native 方法)引用的对象


在可达性分析算法中不可达的对象,也并不是非死不可,只是暂时处于“缓刑”阶段。宣告 对象死亡 至少要经历两次标记过程:对象进行第一可达性分析之后发现没有与GC Roots 相连的引用链,它会被第一次标记并且进行一次筛选,筛选的条件是:此对象是否有必要执行 finalize( )方法。当对象没有覆盖finalize( )方法,或者finalize( )方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行” 。

如果这个对象被判定有必要执行finalize( )方法,那么这个对象将会放置在一个F-Queue 队列中,稍后由虚拟机自动建立的、低优先级的Finalizer线程去执行(触发这个方法)它。finalize()方法是对象逃脱死亡的最后一次机会,稍后GC 将对F-Queue对象进行第二次小规模的标记,如果对象要在finalize()中成功解救自己只要重新与引用链上的任何一个对象建立关联即可,那么它将在第二次标记时被移除“即将回收”的集合;如果还没有逃脱那基本上就真的被回收了。

5.方法区回收

方法区(永久代)垃圾回收的主要回收 两 部分内容:废弃的常量无用的类

废弃的常量:没有任何对象引用常量池中的该常量(字面量);也不存在其他地方对该常量(字面量)的引用。

无用的类:1、该类所有的是实例对象都已被回收,或者说堆中没有该类的任何实例。2、加载该类的ClassLoader 已经被回收。3、该类对应的Java.lang.Class对象没有在任何地方被引用。无法在任何地方通过反射访问的方式方位该类的方法。

6.垃圾收集算法

  一、标记清除算法:

        标记出所有要回收的对象,标记完成后统一回收所有被标记的对象。缺点:1.效率问题,标记和清除的效率都不高。2.容易产生大量不连续的内存碎片,导致给较大兑现分配内存空间时无法找到满足内存需求的连续空间而不得不进行另一次的垃圾回收操作

  二、复制算法:

        将内存划分为相等的两块,每次只用其中的一块,这块内存用完了,将还活着的对象复制到另一块内存上。这块内存一次性清理掉。

  三、标记整理算法

        让或者对象都向内存的一端移动,然后清理掉边界以外 的内存。

所谓的分代收集算法就是在不同的 代 次用上述三中不同的收集算法。新生代采用复制算法,老年代采用一或者三算法