简单说一下java垃圾回收方式

一.什么是垃圾

java中,什么样的对象是垃圾?有人说:没有被引用的对象就是垃圾对象.我一开始对此也是深信不疑的,但是当年我这么回答面试官的时候,得到的是一个大大的白眼.

判断一个对象是否是垃圾,有两种算法,一种是引用计数法,但是,这种方法解决不了循环引用的问题.

/**循环问题*/
public class Demo{
    public Demo instance;
    public static void main(String[] args) {
        Demo a=new Demo();
        Demo b=new Demo();
        a.instance=b;
        b.instance=a;
        a=null;
        b=null;
    }
}

简单说一下java垃圾回收方式_第1张图片

另外一种方法,可以解决这种循环引用问题,那就是可达算法.关于可达算法,就我目前所知道的,有两种解释:
大众说法:
通过一系列的称谓“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所有走过的路径为引用链,当一个对象到GC Roots没有任何引用链项链时,则证明此对象时不可用的.
简单说一下java垃圾回收方式_第2张图片
某位前辈的理解:
选取一个对象作为GC Roots,调用其它对象去指向这个GC Roots,如果这些对象最终到达GC Roots,那表明所选取的对象不是垃圾.反之,如果对象到不了GC Roots,那么所选取的对象就是垃圾对象,就可以进行垃圾回收了.(这是一种说法);
对象指向GC Roots所形成的链条叫GC链.
简单说一下java垃圾回收方式_第3张图片
至于这两种方法谁对谁错,这就要看个人的水平了.
不管怎么样,垃圾反正是产生了,那么接下来就是该怎么回收垃圾了.

二.怎么回收垃圾

1.静态对象什么时候变成垃圾被回收

在说垃圾回收前,先说一个题外话,我上面所说的垃圾对象,其实是指一般的对象,因为静态对象有些不同.
我经常听人说:静态方法随着类的加载而加载,随着类的消失而消失.但是,现在在我看来,这种说法是有问题的.
因为,静态对象要成为垃圾被回收,要满足三个条件:
1. 这个类的对象变成了垃圾
2. 加载这个类的类加载器变成了垃圾
3. 关于这个对象的class对象也变成了垃圾
只有满足这三个条件,静态对象才会变成垃圾被回收,要不然静态对象会一直存在于永久带中.

2,新生代和年老代

既然要说垃圾回收,那么我们就先来看看跟垃圾回收密切相关的堆内存(新生代和年老代)
简单说一下java垃圾回收方式_第4张图片
简单说一下java垃圾回收方式_第5张图片
如图所示:
堆内存按1:2被划分成了年轻代(新生代)和年老代.新生代又被按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区
关于分区,我只讲到这里,有兴趣的可以自己研究.

3.垃圾回收算法

1.标记清除算法

简单说一下java垃圾回收方式_第6张图片
简单说一下java垃圾回收方式_第7张图片
简单说一下java垃圾回收方式_第8张图片
如图所示:标记清除算法分成两步,第一步,标记要回收的垃圾对象,第二步就是清除被标记的垃圾对象.
同样,如图所示,标记清除算法会产生大量的内存碎片,而且效率低.所以,为了解决这个问题,出现了复制清除算法.

2.复制清除算法(专门用于处理年轻代垃圾的)

简单说一下java垃圾回收方式_第9张图片
简单说一下java垃圾回收方式_第10张图片
简单说一下java垃圾回收方式_第11张图片
如图所示,所谓复制清除算法,就是在要进行垃圾回收的时候,先将活着的对象整齐的复制到一块空闲区域,然后再将原来的区域的垃圾全部清除.
复制清除算法的优点:效率高于标记清除算法,活着的对象是整齐排列的,没有内存碎片.
但是这个方法的缺点也很明显,那就是浪费空间.,毕竟如果按照1:1比例来划分空间的话,那么将会有50%的空间被浪费.不过,在jvm中,年轻代空间并不是按照1:1来划分的,而是按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空,这样的过程也被叫做Minor GC,每进行Minor GC一次,存活着的对象的年龄就会加1,当存活着的对象的年龄到达15岁时,就会被送进年老代.
当然,当整个当survivor1区不足以存放 eden和survivor0的存活对象时,也会将存活对象直接存放到年老代。若是年老代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

3.标记清理算法(年老代)

简单说一下java垃圾回收方式_第12张图片
将活着的对象一个接一个的按顺序排好,然后再清除变成垃圾的对象.这种方法不会造成碎片,也不会造成内存的浪费.但是效率不高.所以,这种方法不适合在年轻代使用,而是在对象生命力很顽强的年老代使用

4.分类算法

所谓分类算法,就是根据内存的不同,采用不同的垃圾回收方式(上面的1,2,3)进行垃圾回收.

暂时就先说到这里,因为再说下去,还会有什么GC停顿以及垃圾收集器等.如果大家想要了解更多的垃圾回收的知识,可以看类似<<深入理解Java虚拟机:JVM高级特性与最佳实践>>等书籍.毕竟这些书是我的一位前辈推荐给我的.
简单说一下java垃圾回收方式_第13张图片

你可能感兴趣的:(jvm)