JAVA垃圾回收机制

时间:2022-04-21 00:03:00

一、 Java的垃圾回收机制

      它使得Java程序员在编写程序的时候不需要考虑内存管理。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。程序员可以手动执行System.gc(),通知GC运行,但Java语音规范并不能保证GC一定会执行。

二、  如何判断哪些对象需要回收呢

1. 引用计数法(推荐不使用此方法):给对象中添加一个引用计数器, 当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。

2. 根搜索算法:通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象不可用的。

三、JVM的4种引用和使用场景

1. 强引用-StrongReference

      强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。在程序内存不足(OOM)的时候也不会被回收,使用方式:

String str = new String("str");

2. 软引用-SoftReference

     软引用在程序空间内存不足时,会被回收。软引用可用来实现内存敏感的高速缓存

     软引用可以和一个引用队列ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

3. 弱引用-WeakReference

        只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

        弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

4. 虚引用-PhantomReference

       虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样, 在任何时候都会被垃圾回收器回收。

        虚引用主要跟踪对象被垃圾回收器回收的活动。虚引用必须和引用队列ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

       ReferenceQueue queue = new  ReferenceQueue ();      

        PhantomReference pr = new PhantomReference(object,queue);

        若一个对象的引用类型有多个,那到底如何判断它的可达性呢?规则如下(单弱多强
        单条引用链的可达性以最弱的一个引用类型来决定。
        多条引用链的可达性以最强的一个引用类型来决定。

四、典型的垃圾收集算法

     在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。由于Java虚拟机规范并没有对如何实现垃圾收集器做出明确的规定,因此各个厂商的虚拟机可以采用不同的方式来实现垃圾收集器,所以在此只讨论几种常见的垃圾收集算法的核心思想。

1. Mark-Sweep(标记-清除)算法

      这是最基础的垃圾算法,是因为它最容易实现。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。具体过程如下图所示:
JAVA垃圾回收机制

缺点:效率问题

         空间问题:标记清除之后会产生大量不连续的内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发一次垃圾回收动作。

2. Copying(复制)算法

      它将内存分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。回收新生代,回收比例较大。具体过程如下图所示:

JAVA垃圾回收机制


3. Mark-Compact(标记-整理)算法

      该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。具体过程如下图所示:

JAVA垃圾回收机制

4. 分代收集算法

      在新生代中,每次垃圾收集时都会发现有大批对象死去,只要少量存活,采用复制算法。老年代中对象存活率较高,没有额外空间对它进行分配担保,就必须使用”标记-清理“和”标记-整理“算法来进行回收。

五、GC用的可达性分析算法中,哪些对象可以作为GC Roots对象?

1. 虚拟机栈中引用的对象。

2. 本地方法栈中引用的对象。

3.方法区中的静态成员或常量引用的对象。

参考资料:

《深入理解Java虚拟机》