字节跳动青训营笔记-bitdance--GC方式

147 阅读4分钟

[这是我参与「第四届青训营 」笔记创作活动的第5天]

GC方式

Minor GC

新生代(由 Eden and Survivor 组成)的垃圾收集叫做Minor GC。注意:

  • 当jvm 无法为新建对象分配内存空间的时候Minor GC被触发,例如新生代空间被占满。因此新生代空间占用率越高,Minor GC越频繁。
  • 当空间被占满,它下面的所有对象都会被复制,而且堆顶指针从空闲空间的零位置移动。因此取代传统的标记清除压缩算法,去清理Eden区和Survivor区,因此Eden和Survivor区无内存碎片产生。
  • 在Minor GC期间,实际上Tenured区被忽略,实际上Tenured区引用young区的对象被当作GC roots。在标记期间young区引用的Tenured区对象的对象会被忽略。
  • 反对所有Minor GC都会触发“stop-the-world”这一观点。在大多数应用中,忽略"stop-the-world"停留时长。不可否认的是新生代中的一些对象被错误当成垃圾而不会被移动到Survivor/Old区。

Major GC

Major GC清理Tenured区,但是HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了且明确的定义,所以对于Major GC需要问清楚是指full GC还是old GC。

Full GC

收集整个堆,包括young gen、old gen、perm gen


针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  • Partial GC:并不收集整个GC堆的模式
    • Young GC:只收集young gen的GC
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
    • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式
  • Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

Major GC通常是跟full GC是等价的,收集整个GC堆。但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了,当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是old GC。

  • young GC:当young gen中的eden区分配满的时候触发。注意young GC中有部分存活对象会晋升到old gen,所以young GC后old gen的占用量通常会有所升高。
  • full GC:当准备要触发一次young GC时,如果发现统计数据说之前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先触发一次单独的young GC);或者,如果有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;或者System.gc()、heap dump带GC,默认也是触发full GC。

Minor、Full GC触发条件

Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件

(1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法区空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

回收对象

对于用可达性分析法搜索不到的对象,GC并不一定会回收该对象。要完全回收一个对象,至少需要经过两次标记的过程。

  • 第一次标记:对于一个没有其他引用的对象,筛选该对象是否有必要执行finalize()方法,如果没有执行必要,则意味可直接回收。
  • 第二次标记:如果被筛选判定位有必要执行,则会放入FQueue队列,并自动创建一个低优先级的finalize线程来执行释放操作。如果在一个对象释放前被其他对象引用,则该对象会被移除FQueue队列。

Full GC为什么那么慢

  • 元数据区的回收算法效率低,虚拟机规范Class回收条件比较苛刻
  • Full GC回收新生代、老年代、元数据区/永久代。从这个角度讲,多回收了方法区,增加了总的回收耗时。

为什么Yong GC比Old GC慢?

  • 新生代复制算法比较快。Eden区回收时直接全部清空,存活的对象存放到内存容量比较小的s1,少了解决内存碎片整理 加上直接copy的速度,效率很高。
  • (牺牲时间换空间)老年代标记清除算法会导致内存碎片化,因此就引入了标记整理算法,执行完毕后,存活的对象会按序放置,移动对象的内存地址(重点),来解决碎片化,但是执行时间较长。
  • \