目录
4.2.3 Parallel Scavenge收集器(新生代收集器,并行GC)
4.2.4 Serial Old收集器(老年代收集器,串行GC)
4.2.5 Parallel Old收集器(老年代收集器,并行GC)

JVM通过双亲委派机制对类进行加载。双亲委派机制指一个类在收到了类加载的请求后不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,其父类在接收到该类加载请求后优惠委派给自己的父类,以此类推,这样所有的加载请求都被向上委派到启动类加载器中。若父类加载器在接收到类加载请求后发现自己也无法加载该类(通常原因是该类的 Class 文件在父类加载路径中不存在),则父类会将该信息反馈给子类并向下委派子类加载器加载该类,直到该类被加载成功,若找不到该类,则JVM会抛出ClassNotFound异常。
双亲委派类加载机制的类加载流程如下:
唯一性和安全性(确保优先采取 启动/扩展/应用 类加载器来加载类)
扩展性/灵活性就没那么好(遵循双亲委派机制的类加载,某些场景下可能没法事先知道需要加载的类名(比如:jdbc中的代码,jdk是无法知道数据库驱动类的类名))
GC:堆,方法区;其他没有
Java语言,是不用程序员自己分配内存,也不用自己回收内存。 => 原因:jvm中,实现了垃圾回收机制(自动回收)。
引用计数描述的算法为:
给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死"。
引用计数法实现简单,判定效率也比较高,在大部分情况下都是一个不错的算法。比如Python语言就采用引用计数法进行内存管理。
但是,在主流的JVM中没有选用引用计数法来管理内存,最主要的原因就是引用计数法无法解决对象的循环引用问题。
为了解决引用计数法的循环引用问题,Java还采用了可达性分析来判断对象是否可以被回收。具体做法是首先定义一些GC Roots对象,然后以这些GC Roots对象作为起点向下搜索,如果在GC Roots和一个对象之间没有可达路径,则称该对象是不可达的。不可达对象要经过至少两次标记才能判定其是否可以被回收,如果在两次标记后该对象仍然是不可达的,则将被垃圾收集器回收。
GC Roots:垃圾回收要检查的根节点
引用链:某个对象到达GC Roots的路径(对象与对象之间的连接关系)
"标记-清除"算法是最基础的收集算法。算法分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

缺陷:
"复制"算法是为了解决"标记-清理"的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。

缺陷:
标记过程仍与"标记-清除"过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。

针对不同的对象类型,JVM才用了不同的垃圾回收算法,该算法被称为分代收集算法。在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。
两个GC的特性:
- 新生代GC:又叫Minor GC,采取复制算法,效率比较高。
- 老年代GC:又叫Major GC,采取标记清除/标记整理算法;效率比较差,一般比新生代GC慢10倍以上。

![]()
新生代收集器(复制算法);单线程;不常用
新生代收集器(复制算法);多线程搭配;CMS方案
新生代收集器(复制算法) => 吞吐量优先;适用性能优先的程序。
老年代收集器(标记整理法);单线程
老年代收集器(标记整理法);吞吐量优先
所以在吞吐量优化的程序,只有一种选择:Parallel Old+Parallel Scavenge
(1)初识标记:标记GC Roots能直接关联的对象,需要STW
(2)并发标记:进行GC Roots引用链追踪的过程(搜索引用路径)
(3) 重新标记:修复第2个阶段用户线程同时执行时,产生标记变动的总录,需要STW
(4) 并发清除:并发消除垃圾
(1)CPU比较敏感:用户体验优先,就意味吞吐量稍微低一点(单次停顿时间短,整个停顿时间长一点)=>CPU利用率下降
(2)浮动垃圾问题(浮动垃圾:第4个阶段用户线程并发执行时产生的垃圾,在此次GC无法回收,称为浮动垃圾)会出现两个问题:
并发清除阶段用户线程创建的对象超出预留空间大小=>再次触发另一次的老年代GC
说明:CMS本身就是老年代GC,所以这里就是老年代gc时,又触发一次老年代gc,而者年代gc是比较耗时(效率比较低)
方式:采取老年代gc的后备方案:Serial Qid收集器进行回收
(3)内存碎片问题
标记清除算法就会带来这个问题;内存碎片只是现象,对GC的影响:可能导致提前触发GC
说明:所有可用空间足够,但连续的可用空间不足存放大对象
说明:使用G1,堆的内存划分,就不是一个新生代(E区*1+S区*2)及一个老年代
内存划分方案:把堆划分为多个相同大小的region区,动态分配为E区,S区,或T区(Tenured区,老年代)
新生代回收:回收多个E区+多个S区,复制存活对象到空的region区(动态指定它为S区)
老年代回收:分为4个阶段
(1)初识标记:和cms类似(标记GC Roots关联的对象,STW),不同的是,可以和新生代gc同时执行
(2)并发标记:和cms类似,多:优先回收(Garbage First,G1名词的由来)=>直接回收存活率低或几乎没有存活的region
(3)最终标记:和cms类似
(4)筛选回收:筛选存活率低的region回收