Java垃圾回收机制(GC)简述
Java垃圾回收机制:简单的意思就是JVM释放没有被引用的内存空间的过程;
什么样的对象才是垃圾? 对于Java对象来讲,如果说这个对象没有被任何对象所引用该对象就是无用的,此对象就被称为垃圾,其占用的内存也就要被销毁。Java的对象并没有作用域,而是对Java对象的引用有作用域 ,gc对超出作用域的对象/引用计数为空的对象等手段清除空间内存,补充一些诸如停止其他线程执行、运行finalize等。那么自然而然的就引出了我们的第二个问题,判断对象为垃圾的算法都有哪些?
标记垃圾的算法
Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。我们首先来介绍引用计数法。
引用计数:一个对象被引用计数器加一,取消引用计数器减一,引用计数器为0才能被回收。优点:简单。缺点:不能解决循环引用的问题,比如A引用B,B引用A,但是这两个对象没有被其他任何对象引用,属于垃圾对象,却不能回收;每次引用都会附件一个加减法,影响性能。
标记清除法:分为两个阶段:标记阶段和清除阶段。标记阶段通过根节点标记所有可达对象,清除阶段清除所有不可达对象。缺点:因为清除不可达对象之后剩余的内存不连续,会产生大量内存碎片,不利于大对象的分配。
复制算法:将内存空间分成相同的两块,每次只是用其中的一块,垃圾回收时,将正在使用的内存中的存活对象复制到另外一块空间,然后清除正在使用的内存空间中的所有对象,这种回收算法适用于新生代垃圾回收。优点:垃圾回收对象比较多时需要复制的对象恨少,性能较好;不会存在内存碎片。缺点:将系统内存折半。
标记压缩算法:是一种老年代回收算法,在标记清除的基础上做了一些优化,首先从根节点开始标记所有不可达的对象,然后将所有可达的对象移动到内存的一端,最后清除所有不可达的对象。优点:不用将内存分为两块;不会产生内存碎片。
分代算法:新生代使用复制算法,老年代使用标记清除算法或者标记压缩算法。几乎所有的垃圾回收期都区分新生代和老年代。
分区算法:将整个堆空间分成很多个连续的不同的小空间,每个小空间独立使用,独立回收。为了更好的控制gc停顿时间,可以根据目标停顿时间合理地回收若干个小区间,而不是整个堆空间,从而减少gc停顿时间。
可达性分析算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
那么什么对象可以作为GCRoot?
•虚拟机栈中的引用对象
•方法区中的常量引用对象
•方法区中的类静态属性引用对象
•本地方法栈中的引用对象
•活跃线程中的引用对象
可达性分析算法如下图所示
那么不可达的对象是否是必死之局呢?答案也是否定的 在可达性分析法中不可达的对象,它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize 方法。当对象没有覆盖 finalize 方法,或 finalize方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。