常见GC算法
- 引用计数法: 每个对象都有一个计数器, 对象被引用一次, 计数器+1, 当对象引用失败一次. 计数器-1, 当对象计数器等于0, 说明对象没有被应用, 就可GC
优: 运行过程中, 可随时检查对象计数器, 进行GC, 且GC过程, 应用无需暂停, 执行速度快(单个对象GC不会影响其他对象), 内存不足, OOM
缺: 存在循环引用问题(A引用B, B引用A, A=null, B=null. A,B永远不会GC), 随时都在GC, 占用CPU
- 标记清除: 先标记( 从root进行可达性分析, 标记被引用的对象), 再清除(清除那些没被引用的对象)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/92fff9d05bc75d0c426b5eee6d9b7217.png)
优; 解决循环引用问题
缺: 效率低下, 需要遍历所有对象, 碎片化严重, 清理出来的内存不连续, 当new大对象时, 容易爆OOM
- 标记压缩: 标记需要回收的区域, 进行回收, 将碎片化的空间进行压缩
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/91641be6b793bf96c9d157f270e29760.png)
优: 解决标记清除的碎片化问题
缺: 需要移动内存位置, 效率降低
- 复制算法: 将空间一分为二(只使用其中一块空间进行存储), 进行清除的时候, 将存活对象复制到另外一块空间, 原本的空间全部清除, 解决移动内存问题
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fd0e3bb53cbe53f24e047a4940cf6903.png)
优: 解决标记清除存在的内存移动问题
缺: 对空间的浪费较为严重, 不适用内存空间垃圾较少的情况
复制算法在JVM年轻代的应用
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ec4ce3456db2d08d0fff0130815c60f0.png)
1. GC开始前, 对象分布于Eden, s0区, s1区为空
2. GC开始, Eden中的存活对象全部复制到s1中, s0区中存活对象根据他们的年龄值决定去向
使用-XX:MaxTenuringThreshold设置年龄阈值, 超过该阈值, s0中对象移到老年代, 未达到, 对象则移动到s1中
3. GC完成, 清空Eden, s0区域, s0与s1交换角色, 重复步骤1, 直到"s1"被填满, 然后将"s1"中对象全部移到老年代中
优: 垃圾对象较多时, 效率高, 无碎片化
缺: 垃圾较少, 不适用, 如:老年代, s0/s1一个时刻只能使用其中一块, 内存使用率低
分代算法: 年轻代采用复制清除, 老年代使用标记清除/压缩
垃圾收集器及内存分配
- 串行垃圾收集器: GC过程, 只有一个线程工作, 且应用要停止运行(Stop-the-world), 等待GC完成.
public class GcTest {
public static void main(String[] args)