JVM 篇:HotSpot GC

注:HotSpot 是 JDK 自带的虚拟机类型
如果对垃圾回收的基本概念不是很了解,可以点击 GC 基本概念 前往了解。

HotSpot 使用可达性分析算法来获知哪些对象是有用的,然后把没用的对象回收掉。具体过程为:

  1. GC 时程序中各线程会跑到 安全区域 里面离自己最近的 安全点 更新 OopMap 的数据(栈帧中引用的位置),然后阻塞自己
  2. 通过 OopMap 记录的引用位置快速的枚举 GC Roots,然后开始可达性分析
  3. 使用垃圾收集器回收内存

垃圾收集器

在这里插入图片描述

  • Young generation 表示新生代,Tenured generation 表示老年代
  • 图中有连线关联的表示可以配合使用。
    • 从上图可以知道 G1 是唯一一个可以同时处理新生代和老年代的收集器,其他的都要有一个新生代的收集器和一个老年代的收集器配合。
    • 可以看到老年代中 CMS 和 Serial Old 有交集,意思是当 CMS 收集失败的时候会使用 Serial Old 来代替。
新生代收集器
  • Serial:停止所有用户线程(别名 Stop the world),使用一条 GC 线程来进行垃圾回收。
  • ParNew:Serial 的升级版,使用多条 GC 线程来回收。
  • Parallel Scavenge:过程和 ParNew 一模一样,不同在于这是以吞吐量优先的收集器。
老年代收集器
  • Serial Old:Serial 的老年代版本,Serial / Serial Old 是 client 模式的标配(用户桌面程序,内存一般很小)。
  • Parallel Old:Parallel Scavenge 的老年代版本,Paraller / Parallel Old 是吞吐量优先的收集器配套方案。
  • CMS(Concurrent Mark Sweep):JDK7 和 JDK8 的默认老年代收集器。特点:并发收集,低停顿。
    • CMS 工作过程:
      • 初始标记:标记 GC Roots 能直接关联的对象,需要 Stop the world
      • 并发标记:GC Roots Tracing,与用户线程同时执行。
      • 重新标记:对并发标记的矫正(因为与用户线程同时执行,可能会发生引用变化的情况),需要 Stop the world
      • 并发清除:开始回收垃圾,与用户线程同时执行。
    • 缺点:
      • 通过名字可以得知,内部使用的是 标记-清除算法,所以会产生很多内存碎片。
      • 因为最后一步是 并发清除,所以会产生许多浮动垃圾(并发的用户线程产生的垃圾),这部分垃圾需要等到下一次 Full GC 才能够回收。同时因为有这些浮动垃圾的存在,老年代需要预留一些内存来存放,所以 CMS 不能像其他收集器一样等到老年代区域满了之后才开始 GC。
G1
  • JDK6 的时候开始研发,JDK7 的时候才开始商用,计划用来取代 CMS。
  • G1 收集的范围是整个堆,堆被分成多个独立的区域(region),虽然还保留着新生代和老年代的区别,但是它们不再是物理上的隔离了。
  • G1 的一个特色就是它可以建立可预测的停顿,G1 会维护一张列表记录 region 的回收优先级(越有回收价值的 region 优先级越高),所以可以在规定的停顿范围内回收最具有回收价值的区域,Garbage First 就是 G1 名字的由来。
  • G1 把内存化整为零后,需要靠 RememberSet 来避免全堆扫描(即回收新生代内存时不会扫描老年代的区域)。
  • G1 的工作工程与 CMS 很相似,只有最后一步有明显的区别,CMS 最后一步是并发清除,而 G1 是筛选回收,会发生 Stop the world,使用多线程来执行回收,好处是不会产生浮动垃圾。
  • G1 采用 复制算法 来回收新生代,使用 标记-整理算法 来回收老年代,所以不会产生内存碎片。

内存分配与回收策略
  • 对象优先在 Eden 区分配
  • 大对象直接进入老年代(由 -XX:PretenureSizeThreshold 参数决定大小阀值)
  • 长期存活的对象进入老年代(GC 年龄,由 -XX:MaxTenuringThreshold 决定年龄阀值)
  • 动态对象年龄判断(当同一年龄的对象的大小超过 survivor 区的一半,则大于或小于这个年龄的就会直接进入老年代)
  • 空间分配担保(survivor 区域不足以存放 GC 后存活的对象时,survivor 中原先的对象就会进入老年代,然后再存放此次 GC 后的对象)

杂谈:

  • 新生代使用 复制算法 来进行垃圾回收,所以不会产生内存碎片;老年代只有 CMS 采用了 标记-清除算法,所以只有它会产生内存碎片。
  • 新生代的垃圾收集被称为是 Minor GC,而老年代被称为 Major GC / Full GC。后者比前者慢 10 倍以上。
  • 使用 System.gc(); 显式发动 GC,使用 -XX:PrintGCDetails 可以查看内存回收的情况。

  以上内容为阅读 深入理解Java虚拟机(第2版)后的笔记及对 JDK8 的实践补充。看完这本书后最大的感觉就是,,,再看一遍,很多原来理解不了的知识点就可以看懂了,因为很多内容是前后呼应的。有兴趣的可以去阅读这本书,强推。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值