JVM(七)垃圾回收机制---JVM如何启动垃圾回收器

我们都知道垃圾回收器是JVM自己启动的,我们一般不调用它,可以使用system.gc()调用垃圾回收器,但是也不一定什么时候才会执行

在JVM规范中并没有规定内存回收的动作,由gc收集器自己决定,那么JVM如何发起内存回收这个动作呢?


 

枚举根节点

 由第五篇笔记我们知道一般可以作为GC roots的对象一般在方法区和虚拟机栈(局部变量表)中,那么也就是说GC  roots一般在全局性性引用和执行上下文中(线程执行的环境都存储在栈帧中)中,也就是这些引用指向的对象作为GC roots。那逐个检查这些引用还是否存在,消耗时间。

而且我们在执行GC时,必须停掉所有的线程(stop the world),防止在GC执行的时候,对象的引用关系还在不断发生变化,保证一致性,称为GC停顿。

那么在目前主流的虚拟机里都是准确式GC,也就是在GC停顿后,它应该知道这些引用的位置,而不是一一扫描,这样能有效减少GC停顿时间。那么当线程被停掉以后,gc如何知道上下文引用的位置呢?

在HotSpot中采用OopMap的数据结构来实现,加载完类就记录在对象引用的位置,在JIT编译时也会在特定位置记录下栈和寄存器哪些位置是引用,这些特定的位置就叫做安全点。因为在每一条指令执行都去记录的话,效率太低,所以设置安全点


 

安全点(safepoint)

在oopmap的协助下,虚拟机就可以快速准确完成 GC roots枚举。但是我们知道程序在执行的时候引用关系一直在变化,如果把这些位置都存到oopmap中,oopmap也要占很大一部分内存,且存在很大的时间开销,所以就设置安全点,只有在安全点的时候,线程才能停下来执行gc动作。那么就涉及到一个程序中设置多少个安全点比较合适,安全点该设置在那些位置。

首先安全点的数量,太多,起不到安全点的作用,太少,gc执行次数少,不利用内存及时回收。

所以安全点的位置就相当重要,基本指令执行时间太少,如果安全点设置在普通指令范围,(?)一般设在程序长时间执行为标准选定,方法调用,循环跳转,等这些指令才能产生safepoint。

那么gc如何让线程在安全点停下来呢?

(1)抢先式中断:gc发生,停掉所有线程,不在安全点的线程跑到最近的安全点(不用)

(2)被动式中断:gc在安全点设置标志,线程到安全点检查安全点的gc标志,如果有gc要发生把自己挂起

安全区域 

安全区域:在其中任一点进行根节点枚举都是安全的,也就是枚举前后引用一致。

设置安全点虽然让执行的线程在比较短的时间到达安全点执行gc,但是这个gc动作可能会漏掉正在被阻塞的线程,被阻塞的线程收不到JVM的中断请求,也就是gc请求,对于这种情况,需要安全区域。

安全区域是引用关系不会发生变化的区域,在这个区域的线程,开始GC时都是安全的。当线程进入安全区域,就是对自己标志一个状态,这个时候有gc可以不用管在这个区域的线程,当线程要离开这个区域时,检查gc是否完成,完成则继续执行,没有完成自己挂起 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值