## 分代收集理论
### 3个假说
* 弱分代假说:绝大多数对象都是朝生夕灭的。(设计了年轻代)
* 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。(设计了老年代)
* 跨代引用假说:跨代引用相对于同代引用仅占极少数。(实际Java应用中,可能会存在年轻代的对象跨代引用了老年代的对象)(设计了`记忆集`,在新生代上建立全局的记忆集,把老年代划分为若干个小块,标识出老年代的哪一块内存会存在跨代引用,此后在Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描)
### 分代实现
![](https://img.kancloud.cn/24/13/241383bdd98b8d68858b9fe1586268ba_1252x516.png)
HotSpot虚拟机中,根据对象存活周期的不同,将内存划分为几块。一般是将Java堆分为新生代和老年代,比例为`2:1`;新生代又细分为`Eden`区、`From Survivor`区和`To Survivor`区,比例为`8:1:1`。不同的代采用不同的回收算法:
* 新生代:复制算法
* 老年代:标记-清除算法,或者标记-整理算法
### 定义一些关于GC的名词
1. 部分收集(Partial GC): 不是完整收集Java堆的收集。
* 新生代收集(Minor GC/Young GC):只是新生代的收集。
* 老年代收集(Major GC/Old GC):只是老年代的收集。目前只有CMS收集器会有单独收集老年代的行为。
* 混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。
2. 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。
## 垃圾收集算法
知道了如何判定**无用的对象**、**废弃常量**和**无用的类**后,接下来就是将这些无用的对象给回收掉。
如下是常用的3种垃圾收集算法。
### 标记-清除
![](https://img.kancloud.cn/73/5a/735a6efe6ff6caf8f94af147e5e4c4dc_1620x980.png)
该算法分为标记和清除两个阶段。
* 标记:遍历所有的 GC Roots,然后将所有 GC Roots 可达的对象标记为存活的对象。
* 清除:遍历堆中所有的对象,将没有标记的对象清除掉。同时清除对象上的标记,以便下一次垃圾回收。
这种方法有2个不足:
1. 效率问题:标记和清除2个过程效率都不高
2. 空间问题:回收后内存会有大量碎片;碎片太多可能导致以后需要分配大对象时,无法找到足够连续的内存不得不提前触发另一次垃圾回收动作。
### 复制(新生代)
![](https://img.kancloud.cn/1b/8b/1b8bf2a00f285696149f4d3a2e633613_1618x978.png)
为了解决效率问题,复制算法出现了。它将可用内存按容量划分为大小相同的两块,每次只使用其中的一块。当这一块内存用完,需要进行垃圾收集时,就将存活的对象复制到另一块上,然后清除掉这一块内存。
这种算法有优有劣:
* 优势:不会产生碎片。
* 劣势:内存缩小为原来的一般,浪费空间。
**为了解决空间利用率问题**,可以将内存分为3块:Eden、From Survivor、To Survivor,比例是8:1:1,每次使用Eden和其中一块Survivor。回收时,将Eden和Survivor中存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才使用的Survivor空间。这样只有10%的内存被浪费。
但是无法保证每次回收都只有不多于10%的对象存活,当Survivor空间不足时,需要依赖其他内存(老年代)进行**分配担保**。
**分配担保**是指如果另一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时(超过10%),这些对象将直接通过分配担保机制进入老年代。
### 标记-整理(老年代)
![](https://img.kancloud.cn/43/93/4393cc6bc80aa5131f1dfefa74939856_1612x984.png)
该算法分为标记和整理两个阶段。
* 标记:遍历所有的 GC Roots,然后将所有 GC Roots 可达的对象标记为存活的对象。(和标记-清除的标记阶段一样)
* 整理:移动所有存活的对象,按着内存地址次序依次排列,然后将末端地址以后的全部内存回收。
这是一种老年代的收集算法,老年代的对象存活时间比较长。
## 参考资料
* 周志明 * 《深入理解Java虚拟机》
* Java虚拟机底层原理知识总结 * https://doocs.github.io/jvm/
- 面试突击
- Java虚拟机
- 认识字节码
- 000Java发展历史
- 000Macos10.15.7上编译OpenJDK8u
- 001熟悉Java内存区域
- 002熟悉HotSpot中的对象
- 003Java如何计算对象大小
- 004垃圾判定算法与4大引用
- 005回收堆和方法区中对象
- 006垃圾收集算法
- 007HotSpot虚拟机垃圾算法实现篇1
- 007HotSpot虚拟机垃圾算法实现篇2
- 007HotSpot虚拟机垃圾算法实现篇3
- 008垃圾收集器
- 009内存分配与回收策略
- 010Java虚拟机相关工具
- 011调优案例分析
- 012一次IDEA的启动速度调优
- 013类文件Class的结构
- 014熟悉字节码指令
- 015类加载机制(过程)
- 016类加载器
- IDEA的JVM参数
- Java基础
- Java自动装箱与拆箱
- Java基础数据类型
- Java方法的参数传递
- Java并发
- 001走入并行的世界
- 002并行程序基础
- 003熟悉Java内存模型JMM
- 004Java并发之volatile关键字
- 005线程池入门到精通
- 006Java多线程间的同步控制方法
- 007Java维基准测试框架JMH
- 008Java并发容器
- 009Java的线程实现
- 010Java关键字synchronized
- 011一些并行模式的熟悉
- 单例模式和不变模式
- 生产者消费者模式
- Future模式
- 012一些并行算法的熟悉
- 面试总结
- 长亮一面