JAVA 垃圾回收机制(一) --- 对象回收与算法初识

##JAVA 垃圾回收机制(一) — 对象回收与算法初识

一、概念

这里说的GC回收,指的是 Java 堆的地方, 深入Java虚拟机之 — JVM的爱恨情仇 文章 中,我们知道了程序计算器,虚拟机栈和本地方法栈都是随线程开启,随线程关闭的,因此这几块区域的内存分配和回收都具备确定性。而Java 堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有程序在运行时,才知道创建了哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的就是这部分内存。
而 GC 关注的也就3个点:

  • 哪些对象需要回收
  • 什么时候回收
  • 如何回收

二、哪些对象需要回收

怎么判断对象是“存活” 的,还是已经"死亡"呢?主要有以下方法:

  • 1.引用计算算法: 给对象添加一个引用计算器,每当有一个地方引用它,则加1,当引用失效,则减1;任何时刻计算器为0的对象就是不可能再被使用的。但它很难解决对象之间相互循环引用的问题,所以主流的Java虚拟机都没有采用这种算法。
  • 2.可达性分析算法:
    通过一系列的 “GC Roots” 的对象作为起始点,从这些起始点开始向下搜索,搜索走过的路径被称为引用链(Reference Chain),当一个对象到GC Roots 没有任何引用链项链,即GC Roots 不可达,则证明此对象是不可用的。

三、什么时候回收

  • 1.在可达性分析算法不可达的对象,也不一定"非死不可’,它会经历两次标记,一是当不可达 GC Roots 时,标记一次并筛选,筛选的条件是该对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或者已经执行过 finalize 方法时,则认为此对象会被回收。
  • 2.上面都是对 Java 堆进行回收,虽说 Java 堆 可以回收70%~95%的空间,但方法区同样可以回收一些资源,方法区主要回收两个部分废弃常量和无用的类。

四、如何回收

  • 4.1 标记-清除算法
    这个算法首先标记处所有需要回收的对象,在标记完成之后统一回收所有被标记的对象。
    看似美好,实则不然,主要有以下两个缺点:
    效率问题:标记和清除两个效率都不高
    空间问题:标记清除后,会产生大量空间碎片,在大对象需要分配空间时,找不到内存,从而又触发 GC 操作。

  • 4.2 复制算法
    基于 标记-清除算法的效率问题,复制算法出现的。
    这种算法是把内存分为相等的两块,一块用来存储对象,当GC操作后,把还存留的对象移动到未存对象的那块内存区域,再把使用过的内存清掉。这样每次都对整个半区进行内存回收,就不用担心内存碎片的问题了。

  • 4.3 标记-整理算法
    标记整理算法,是针对老年代的。它与标记-清除算法一样,但不是对相对进行清除,而是移动到另一端,分两个步骤
    1.标记那些被引用的对象
    2.将被标记的对象移动按顺序移动到一端,然后清除掉可回收的对象

  • 4.4、分代收集算法
    在商业的虚拟机中,都采用 分代收集算法,根据对象存活周期将内存划分为几块,即新生代和老年代;
    在新生代中,每次都有大量对象死去,只有少量活着,就选用复制算法;而老年代的对象存活率比较高,没有额外空间对它进行分配担保,就必须使用 “标记-整理”或者“标记-清理” 进行回收。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章