论GC

2018-11-13  本文已影响0人  小吉快跑呀

几个名词

几种引用

几个分代

  1. 为什么会有分代
    我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能。你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描。

  2. 对象能活多久
    数据证明,我们应用中的对象在80%以上都是秒死亡的,也就是活不过一个GC轮回。

给引用赋空值,但是他却就是不空

A.HELP = new A();
A.HELP = null;
print((A.HELP == null) + "");

这段代码居然可以运行如下:

false

原来,A中进行了这样的操作:

class A {
    static A HELP= null;
    @Override
    void finalize() throws Throwable {
        super.finalize();
        HELP = this;
    }
}

为啥子重写了finalize方法就可以使赋空值无效呢?其实关键是他方法里面的赋值操作,他把自己赋值给了静态变量HELP,下面来说说GC是如何给对象判死刑的

给对象判死刑

当做完第一次可达性分析之后发现目标对象和GC Root并不相连,那么就会去看看需不需要执行对象的finalize方法(finalize没有被执行过或者没有被重写,这两种情况都认为需要执行),认为需要执行finalize的对象都会被加入队列中,否则直接杀死。加入了队列的对象都会排队被系统调用finalize方法,调用过后GC将再标记一次队列中的对象,加入此时对象与GC Root有链接,那么放生,否则GG

被安排的过程
所以说对象可以在finalize方法中自救,不过只有一次机会,因为上面说了,finalize被执行过一次的对象是不会进入队列的,是直接GG的

垃圾收集算法

标记-清除

就是将要回收的块标记出来,然后清掉,这样的问题是会产生很多碎片区域

复制

复制算法就是以一块完整的区域为GC目标,GC它时,将区域中还存活着的对象都复制到另一个空闲区域,然后直接清空整个目标区域,这样就不会产生碎片,但是复制消耗大,并且需要空间大

标记-整理

他和标记清除的不同就是,标记要删除的块之后,它会把存活的对象推向一侧(玩过2048的同学可以感受一下这是什么操作),然后删掉剩余区域

Stop The World

当发生GC时,正在执行Java code的线程必须全部停下来,才可以进行垃圾回收,这就是熟悉的STW(stop the world), 但是并不是说停就停的,线程需要跑到最近的安全点才能够挂起,所以说GC操作耗时,开销大。考虑这样一种情况,某个线程跑不到安全点,也就是说,他本来就挂起了,那么这时候GC操作就很难受,因为它必须要等所有线程都在安全点了才能开始。为了尽量避免这样的情况,又引出了另外一个玩意叫安全区,就是把点扩展为面,在一段区域内,引用关系不会发生变化,这就叫安全区

各种收集器

Serial

单线程啊,不行啊,而且不支持和用户线程并发,在GC的时候会停掉用户线程

ParNew

多线程了,但是还是不支持和用户线程并发

Parallel Scavenge

很像前者ParNew,区别就是后者适合后台工作的应用,就是那种不需要交互的东西,因为这个收集器优化的点不在如何缩短停止掉用户线程的时间长短,而是在于吞吐量( 用户代码运行时间/(用户代码运行时间+GC时间))

Serial Old

和第一个收集器只有收集算法上的区别

Parallel Old

多线程,采用“标记——整理”算法

CMS

使用较多的收集器吧,多线程,它的并发标记和并发清理阶段都可以和用户线程并发执行

G1

除了初始标记阶段,其他阶段都可以并发执行,并发标记阶段、回收阶段可以与用户线程并发,好像很棒棒?但是还不成熟,很水。

一般如何分配

优先放在Eden

科普一哈,年轻代中有两种区,Eden区和Survivor区,通常是8:1的大小关系

当对象不是超级大的情况下,都优先塞进Eden区,要是塞不下了就来一个Minor GC,然后一般就有足够空间放下它。

大对象直接放老年代

在优先分配到Eden区的时候,如果对象大于Eden那就直接放进老年代

在年轻代中活久了的对象放进老年代

这个一看就懂啦,老了就换区啊,一般有一个 触发换区的岁数。对象经历一次GC,岁数就加一

动态年龄判断

感觉这个其实有点像平均年龄的概念,但是又有所区别。在Survivor中相同年龄的对象综合达到Survivor区的一半大小时,超过这个年龄的对象也会转移到老年代

担保机制

考虑这样一种情况,在Minor GC中,年轻代中想要存活下来的对象太多,Survivor区放不下,那这时候咋子办咯。这时候就需要老年代分一部分来存放对象了。但是,这里要知道一个事实,年轻代中到底会有多少对象存活下来在Minor GC完成前系统是无法知道的,因此根本不知道老年代中的可用空间够不够存放多出来的对象。这时候就需要冒险了:担保机制中,老年代每次都会记录有多少对象过来了,这样系统就可以算出一个平均值,当要担保的时候就以这个平均值为参考,认为它就是这次要担保的空间大小,若老年代中的可用空间小于它的话就触发Full GC来清理一波老年代,再来Minor GC

上一篇 下一篇

猜你喜欢

热点阅读