jvm对象从新生代到老年代_JVM 如何确定老年代的对象是活着的(转)

https://www.cnblogs.com/littleLord/p/5380624.html

通过 GC ROOT TRACING 可到达的对象肯定是活着的。但是如果遇到在以下场景,老年代进行 GC 时,如何确保图中 Current Obj 被标记为活着的?

通过扫描新生代。所以 CMS 虽然是老年代的 GC,但仍要扫描新生代。CMS GC 日志中可以看到扫描日志:

[GC[YG occupancy: 270973 K (1145600 K)]

[Rescan (parallel) , 0.2171280 secs]

[weak refs processing, 0.0000700 secs]

[scrub string table, 0.0016420 secs] [1 CMS-remark: 1996330K(2124800K)] 2267303K(3270400K), 0.2190720 secs] [Times: user=2.13 sys=0.00, real=0.22 secs]

Total time for which application threads were stopped: 0.2232820 seconds

Rescan 会扫描新生代和老年代中的对象, parallel 说明此阶段是并行进行的,并且只需要扫描新生代和老年代中活着的对象就可以了。

扫描新生代机制

Minor GC 后新生代的对象全是活着的,并且活着的对象应该很少。所以可以在扫描新生代前进行一次 Minor GC(老年代 GC 前)。CMS 提供参数:

+XX:CMSScheduleRemarkEdenSizeThreshold=2M

# 当 Eden 区占用超过 2M 时,执行可中断的并发预清理(CMS-concurrent-abortable-preclean)

+XX:CMSScheduleRemarkEdenPenetration=50

# 直到 Eden 空间使用率达到 50% 时中断,然后进入重新标记(CMS-Remark)阶段

-XX:CMSMaxAbortablePrecleanTime=5000

# 并发预清理如果超过 5000ms 未完成,直接进入重新标记阶段

如果在可中断的并发预清理阶段发生了一次 Minor GC 就会提前中断此阶段(此阶段在重新标记前,Minor GC 后新生代只剩下少量的活着的对象,就达到了优化效果),但是这个阶段不一定会发生 Minor GC(JVM 自动调度无法控制),也就是最长可能执行5s后进入重新标记阶段。

即然并发预清理阶段不能保证执行一次 Minor GC,CMS 提供另一个参数 +XX:+CMSScavengeBeforeRemark,使 CMS 重新标记阶段前强制进行一次 Minor GC。

好的一面是减少了 CMS-Remark 阶段的 STW 时间,坏的一面是 Minor GC 后紧跟着一个 CMS-Remark,增加整体的 STW 时间。

[CMS-concurrent-abortable-preclean-start]

[GC 7688.465: [ParNew: 1040940K->1464K(1044544K), 0.0165840 secs] 1343593K->304365K(2093120K), 0.0167509 secs]

[CMS-concurrent-abortable-preclean: 1.012/1.907 secs]

[GC[YG occupancy: 522484 K (1044544 K)]

看似不一定能够改善总体的 STW 情况,实际使用时需要根据测试结果调整。

扫描老年代机制

使用了 Card Table(Byte 数组),将老年代的空间分成大小为 512bytes 的块(Card),Card Table 的每一位对应老年代空间中的一个 Card。

并发标记时(此时应用线程继续运行),如果某个对象的引用发生了变化,Card Table 就标记该对象所在的 Card 为 Dirty card。

并发预清理阶段就对于老年代的重新扫描只需要扫描 Dirty card 所在的内存空间,找到所有可能活着的对象。

并发标记时对象的状态:

随后 current obj 的引用发生了变化:

current obj 所在的 card 被标记为了dirty card

随后到了 pre-cleaning 阶段,该阶段的任务之一就是标记这些在并发标记阶段被修改了的对象,之后那些通过 current obj 变得可达的对象也被标记了,同时 Dirty card 标志也被清除:

Card Table 的其他作用

上面的场景是老年代对象被新生代对象引用,另外一个场景刚好相反:新生代对象被老年代对象引用。

当有老年代引用新生代,对应的 Card Table 被标识为 Dirty card(Card Table 中是一个 byte,有八位,约定好每一位的含义就可区分哪个是引用新生代,哪个是并发标记阶段修改过的),Minor GC 通过扫描 Dirty cards 就可以很快的识别老年代引用新生代。

https://www.cnblogs.com/littleLord/p/5380624.html

Tags:JVM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值