论GC

作者: 小吉快跑呀 | 来源:发表于2018-11-13 11:25 被阅读0次

几个名词

  • Minor GC——年轻代中的GC操作
  • Full GC——老年代中的GC操作

几种引用

  • 强引用(Strong Reference)——只要存在,就不会被安排
  • 软引用(Soft Reference)——只有实在没空间准备要凉的时候才会被安排
  • 弱引用(Weak Reference)——下一轮GC到来,就会被安排,不管实际上还够不够空间
  • 虚引用(Phantom Reference)—— 想怎么安排就怎么安排,只是用来告诉持有引用的用户,你的东西被安排了

几个分代

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

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

  • 年轻代——放刚出生的对象
  • 老年代——放老对象,就是那些在年轻代中生存了几个GC轮回的对象
  • 持久代——存放类信息、常量池、静态字段、方法等,一般不会回收了(但是现在被一个叫元空间的东西给替代了,持久代还是归JVM管的一块内存,但元空间就不是了,它直接就是计算机的一块内存)

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

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

相关文章

  • 论GC

    几个名词 Minor GC——年轻代中的GC操作 Full GC——老年代中的GC操作 几种引用 强引用(Stro...

  • 面试官,不要再问我“Java 垃圾收集器”了

    如果Java虚拟机中标记清除算法、标记整理算法、复制算法、分代算法这些属于GC收集算法中的方法论,那么“GC收集器...

  • 面试官,不要再问我“Java 垃圾收集器”了

    如果Java虚拟机中标记清除算法、标记整理算法、复制算法、分代算法这些属于GC收集算法中的方法论,那么“GC收集器...

  • JVM垃圾收集器

    GC的时机 GC从时机上分为两种:Scavenge GC和Full GC Scavenge GC(Minor GC...

  • java常见垃圾收集器

    常见的有Serial GC、ParNew GC、CMS GC、Parallel GC、G1 GC Serial G...

  • FullGC、MinorGC、STW等常见问题如何解答

    什么是Full GC?minor GC? major GC? STW? minor GC:新生代回收的gc( ST...

  • 内存分配与回收策略

    1 Minor GC+Major GC+Full GC (1)Minor GC:新生代GC。因为Java对象大多都...

  • JVM垃圾收集器

    七大垃圾收集器 GC算法(可达性分析,复制,标清,标整)是内存回收的方法论,垃圾收集器就是这些方法论的落地实现: ...

  • Go GC

    1、什么是GC?2、为什么会有GC?3、GC的优点?4、GC的缺点?5、Go中的GC历史6、Go中的GC实现原理(...

  • 通过 gc.log 调优 JVM

    一、GC 日志查看 GC 日志默认是关闭的,需要查看 GC 日志首先需要开启 GC 日志。 常用 GC 日志的配置...

网友评论

      本文标题:论GC

      本文链接:https://www.haomeiwen.com/subject/tjjaxqtx.html