垃圾收集算法

2018-07-18  本文已影响9人  T_log

垃圾收集算法

  1. 在Java内存中,不停的有对象的创建与消亡,在内存一定的情况下,内存的动态分配和垃圾收集都由JVM去帮我们程序员自动完成,那么,JVM在内存回收时的疑问如下

哪些内存需要被回收
什么时候回收
如何回收

  1. 对象已经死了吗?

java对象几乎全部存放在堆中,垃圾收集的主要区域也是Java堆内存。在垃圾收集器进行垃圾收集时,首先要确定哪些对象还存活,不需要回收,哪些对象已经死去,需要被回收。

  1. 引用计数算法

给每个对象一个引用计数器,每当有一个地方引用它时,计数器的值就加一,当引用失效时,计数器的值就减1,任何时刻计数器的值为0的对象,代表不可能在被利用。
引用计数器的优缺点

  1. 实现简单,判断效率高
  2. 难以解决对象之间相互引用的问题
package com.schoki.jvm.chapter2;
/**
 * @author : jzb219@gmial.com
 * @description : 测试 objA objB是否会被回收
 * @date : 2018/7/18 下午3:42
 */
public class ReferenceCountingGC {

    public Object instance = null;

    private static final int _1M = 1024 * 1024;

    /**
     * 该变量的意义在于占点内存,以便在垃圾收集时,可以看到GC日志中,是否会回收
     */
    private byte[] bigSize = new byte[2 * _1M];

    public static void main(String[] args) {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;

        objA = null;
        objB = null;


        //假设发生GC, objA objB是否会被回收
        System.gc();
    }
}

运行结果(JDK1.8)

[GC (System.gc()) [PSYoungGen: 6779K->576K(38400K)] 6779K->584K(125952K), 0.0016589 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 576K->0K(38400K)] [ParOldGen: 8K->509K(87552K)] 584K->509K(125952K), [Metaspace: 3286K->3286K(1056768K)], 0.0075244 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 38400K, used 333K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
  eden space 33280K, 1% used [0x0000000795580000,0x00000007955d34a8,0x0000000797600000)
  from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
  to   space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
 ParOldGen       total 87552K, used 509K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
  object space 87552K, 0% used [0x0000000740000000,0x000000074007f690,0x0000000745580000)
 Metaspace       used 3292K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 363K, capacity 388K, committed 512K, reserved 1048576K

从运行结果可以看到

  1. 第一行中PSYoungGen ,说明收集器采用的是Parallel Scavenge收集器
  2. 6779K->576K(38400K),回收前是6779K,回收后576K,说明虽然objA和objB存在相互引用,但是依然会被垃圾收集器回收掉,从侧面也说明垃圾收集算法采用的不是引用计数算法
  1. 可达性分析算法

通过一些列(注意是很多哦,我特么刚开始以为一个应用里面就一个GC Roots)的成为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(或者说GC Roots到这个对象不可达),则说明这个对象是不可用的
哪些对象可以作为GC Roots

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象--代表应用上下文
  2. 方法区中类静态属性引用的对象
  3. 方法区中,常量引用的对象
  4. 本地方法栈中JNI(一般说native方法)引用的对象(注:这个没太搞明白)

参考
周志明《深入理解Java虚拟机》

写在最后

做一个灵魂和肉体分离的人,灵魂不受肉体的束缚,灵魂可以指挥肉体

上一篇下一篇

猜你喜欢

热点阅读