垃圾回收
java会对内存进行自动分配与回收管理, 使上层业务更加安全, 方便的使用内存实现程序逻辑, 在不同的JVM实现及不同的回收机制中, 堆内存的划分方式是不一样的
垃圾回收的主要目的是清楚不再使用的对象, 自动释放内存
问题: GC是如何判断对象是否可以被回收的呢?
答: 为了判断对象是否存活, JVM引入了GC Roots, 如果一个对象与GC Roots之间没有直接或间接的引用关系, 比如某个失去了任何引用的对象, 或者两个互相环岛状循环引用的对象等, 判决这些对象’死缓’是可以被回收的
问题: 什么对象可以作为GC Roots呢?
答: 类静态属性中引用的对象, 常量引用的对象, 虚拟机栈中引用的对象, 本地方法栈中引用的对象等
以上可以理解为判断对象是否存活的标准
了解一下垃圾回收的相关算法
- 1.最基础的为"标记-清除算法", 该算法会从每个GC Roots出发, 依次标记有引用关系的对象, 最后将没有被标记的对象清除, 但是这种算法会带来大量的空间碎片, 导致需要分配一个较大连续空间时容易触发FGC, 为了解决这个问题, 又提出了第二种算法
- 2.“标记-整理算法”, 该算法类似计算机的磁盘整理, 首先会从GC Roots出发标记存活的对象, 然后将存活对象整理到内存空间的一端, 形成连续的已使用空间, 最后把已使用空间之外的部分全部清理掉
- 3.“Mark-Copy算法”, 为了能够并行的标记和整理将空间分为两块, 每次只激活其中一块, 垃圾回收时只需要把存活的对象复制到另一块未激活空间上, 将未激活空间标记为已激活, 将已激活空间标记为未激活, 然后清除原空间中的原对象
堆内存空间分为较大的Eden和两块较小的Survivor, 每次只使用Eden和Survivor区的一块, 这种情况下, 使用"Mark-Copy"算法减少了内存空间的浪费, “Mark-Copy” 现作为主流的YGC算法进行新生代的垃圾回收
垃圾回收(Garbage Colletor)是实现垃圾回收算法并应用在JVM环境中的内存管理模块, 当前实现的垃圾回收器有数十种, 以下介绍几个列子:
-
Serial回收器是一个主要应用于YGC的垃圾回收器, 采用串行单线程的方式完成GC任务, 其中"Stop TheWorld"简称STW, 即垃圾回收的某个阶段会暂停整个应用程序的执行,FGC的时间相对较长, 频繁FGC会严重影响应用程序的性能
-
CMS回收器(Concurrent Mark Sweep Collector)是回收停顿时间比较短, 目前比较常用的垃圾回收器,它通过初始标记(Initial Mark), 并发标记(Concurrent Mark), 重新标记(Remark),并发清除(ConcurrentSweep)四个步骤完成垃圾回收工作,初始标记和重新标记阶段依然会引发STW(STW即垃圾回收的某个阶段会暂停整个应用程序的执行),而并发标记和并发清除两个阶段可以和应用程序并发执行, 也是比较耗时的操作, 但并不影响应用程序的正常执行
-
Hotspot在JDK7中推出了新一代G1(Garbage-First Garbage Collector)垃圾回收,通过-XX:+UseG1GC参数启用, 和CMS相比, G1具备压缩功能, 能避免碎片问题, G1的暂停时间更加可控, 性能不错
详解G1:
G1将java堆空间分割成了若干相同大小的区域, 即region, 包括Eden, Survivor, O1d, Humongous四种类型, 其中, Humongous是特殊的O1d类型, 专门放置大型对象, 这样的划分方式意味着不需要一个连续的内存空间管理对象, G1将空间分为多个区域, 优先回收垃圾最多的区域, G1采用"Mark-Copy"算法, 有非常好的空间整合能力, 不会产生大量的空间碎片, G1的一大优势在于可预测的停顿时间, 能够尽可能快的在指定时间内完成垃圾回收任务, 在JDK11中, 已经将G1设为默认垃圾回收器, 通过jstat命令可以查看垃圾回收情况