打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
聊聊JVM(六)理解JVM的safepoint
userphoto

2017.10.25 广东

关注


safepoint 安全点顾名思义是指一些特定的位置,当线程运行到这些位置时,线程的一些状态可以被确定(the thread's representation of it's Java machine state is well described),比如记录OopMap的状态,从而确定GC Root的信息,使JVM可以安全的进行一些操作,比如开始GC。

safepoint指的特定位置主要有:

1. 循环的末尾 (防止大循环的时候一直不进入safepoint,而其他线程在等待它进入safepoint)

2. 方法返回前

3. 调用方法的call之后

4. 抛出异常的位置


之所以选择这些位置作为safepoint的插入点,主要的考虑是“避免程序长时间运行而不进入safepoint”,比如GC的时候必须要等到Java线程都进入到safepoint的时候VMThread才能开始执行GC,如果程序长时间运行而没有进入safepoint,那么GC也无法开始,JVM可能进入到Freezen假死状态。在stackoverflow上有人提到过一个问题,由于BigInteger的pow执行时JVM没有插入safepoint,导致大量运算时线程一直无法进入safepoint,而GC线程也在等待这个Java线程进入safepoint才能开始GC,结果JVM就Freezen了。

How to get Java stacks when JVM can't reach a safepoint


JVM在很多场景下使用到safepoint, 最常见的场景就是GC的时候。对一个Java线程来说,它要么处在safepoint,要么不在safepoint。

1. Garbage collection pauses
2. Code deoptimization
3. Flushing code cache
4. Class redefinition (e.g. hot swap or instrumentation)
5. Biased lock revocation
6. Various debug operation (e.g. deadlock check or stacktrace dump)


GC的标记阶段需要stop the world,让所有Java线程挂起,这样JVM才可以安全地来标记对象。safepoint可以用来实现让所有Java线程挂起的需求。这是一种"主动式"(Voluntary Suspension)的实现。JVM有两种执行方式:解释型和编译型(JIT),JVM要保证这两种执行方式下safepoint都能工作。

在JIT执行方式下,JIT编译的时候直接把safepoint的检查代码加入了生成的本地代码,当JVM需要让Java线程进入safepoint的时候,只需要设置一个标志位,让Java线程运行到safepoint的时候主动检查这个标志位,如果标志被设置,那么线程停顿,如果没有被设置,那么继续执行。

例如hotspot在x86中为轮询safepoint会生成一条类似于“test %eax,0x160100”的指令,JVM需要进入gc前,先把0x160100设置为不可读,那所有线程执行到检查0x160100的test指令后都会停顿下来

  1. 0x01b6d627: call   0x01b2b210         ; OopMap{[60]=Oop off=460}      
  2.                                        ;*invokeinterface size      
  3.                                        ; - Client1::main@113 (line 23)      
  4.                                        ;   {virtual_call}      
  5.  0x01b6d62c: nop                       ; OopMap{[60]=Oop off=461}      
  6.                                        ;*if_icmplt      
  7.                                        ; - Client1::main@118 (line 23)      
  8.  0x01b6d62d: test   %eax,0x160100      ;   {poll}      
  9.  0x01b6d633: mov    0x50(%esp),%esi      
  10.  0x01b6d637: cmp    %eax,%esi   

在解释器执行方式下,JVM会设置一个2字节的dispatch tables,解释器执行的时候会经常去检查这个dispatch tables,当有safepoint请求的时候,就会让线程去进行safepoint检查。


聊聊JVM(五)从JVM角度理解线程 说了JVM中的线程类型,其中提到VMThread。VMThread会一直等待直到VMOperationQueue中有操作请求出现,比如GC请求。而VMThread要开始工作必须要等到所有的Java线程进入到safepoint。JVM维护了一个数据结构,记录了所有的线程,所以它可以快速检查所有线程的状态。当有GC请求时,所有进入到safepoint的Java线程会在一个Thread_Lock锁阻塞,直到当JVM操作完成后,VM释放Thread_Lock,阻塞的Java线程才能继续运行。


GC stop the world的时候,所有运行Java code的线程被阻塞,如果运行native code线程不去和Java代码交互,那么这些线程不需要阻塞。VM操作相关的线程也不会被阻塞。


safepoint只能处理正在运行的线程,它们可以主动运行到safepoint。而一些Sleep或者被blocked的线程不能主动运行到safepoint。这些线程也需要在GC的时候被标记检查,JVM引入了safe region的概念。safe region是指一块区域,这块区域中的引用都不会被修改,比如线程被阻塞了,那么它的线程堆栈中的引用是不会被修改的,JVM可以安全地进行标记。线程进入到safe region的时候先标识自己进入了safe region,等它被唤醒准备离开safe region的时候,先检查能否离开,如果GC已经完成,那么可以离开,否则就在safe region呆在。这可以理解,因为如果GC还没完成,那么这些在safe region中的线程也是被stop the world所影响的线程的一部分,如果让他们可以正常执行了,可能会影响标记的结果


可以设置JVM参数 -XX:+PrintSafepointStatistics –XX:PrintSafepointStatisticsCount=1 来输出safepoint的统计信息


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java系列:JVM中的OopMap(zz)
深度揭秘垃圾回收底层,这次让你彻底弄懂她
深入理解JVM之二:内存的垃圾回收算法
10个经典又容易被人疏忽的JVM面试题
jvm介绍(很好的一篇文章)
关于Java性能方面的9个谬论
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服