快速理解Java垃圾回收和jvm中的stw

所属分类: 软件编程 / java 阅读数: 29
收藏 0 赞 0 分享

Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起。

GC时的Stop the World(STW)是大家最大的敌人。但可能很多人还不清楚,除了GC,JVM下还会发生停顿现象。

JVM里有一条特殊的线程--VM Threads,专门用来执行一些特殊的VM Operation,比如分派GC,thread dump等,这些任务,都需要整个Heap,以及所有线程的状态是静止的,一致的才能进行。所以JVM引入了安全点(Safe Point)的概念,想办法在需要进行VM Operation时,通知所有的线程进入一个静止的安全点。

除了GC,其他触发安全点的VM Operation包括:

1. JIT相关,比如Code deoptimization, Flushing code cache ;

2. Class redefinition (e.g. javaagent,AOP代码植入的产生的instrumentation) ;

3. Biased lock revocation 取消偏向锁 ;

4. Various debug operation (e.g. thread dump or deadlock check);

监控安全点看看JVM到底发生了什么?

最简单的做法,在JVM启动参数的GC参数里,多加一句:

-XX:+PrintGCApplicationStoppedTime

它就会把全部的JVM停顿时间(不只是GC),打印在GC日志里。

2016-08-22T00:19:49.559+0800: 219.140: Total time for which application threads were stopped: 0.0053630 seconds

这是个很有用的必配参数,可以打出几乎一切的停顿……

但是,在JDK1.7.40以前的版本,它居然没有打印时间戳,所以只能知道JVM停了多久,但不知道什么时候停的。此时一个土办法就是加多一句“ -XX:+PrintGCApplicationConcurrentTime”,打印JVM在两次停顿之间的正常运行时间(同样没有时间戳),但好歹能配合有时间戳的GC日志,反推出Stop发生的时间了。

2016-08-22T00:19:50.183+0800: 219.764: Application time: 5.6240430 seconds

如何打印出事哪种原因导致的停顿呢?

再多加两个参数:-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1

此时,在stdout中会打出类似的内容

vmop [threads: total initially_running wait_to_block]1913.425: GenCollectForAllocation [ 55 2 0 ] [time: spin block sync cleanup vmop] page_trap_count[ 0 0 0 0 6 ] 0

此日志分两段,第一段是时间戳,VM Operation的类型,以及线程概况

total: 安全点里的总线程数

initially_running: 安全点时开始时正在运行状态的线程数

wait_to_block: 在VM Operation开始前需要等待其暂停的线程数

第二行是到达安全点时的各个阶段以及执行操作所花的时间,其中最重要的是vmop

spin: 等待线程响应

safepoint号召的时间

block: 暂停所有线程所用的时间

sync: 等于 spin+block,这是从开始到进入安全点所耗的时间,可用于判断进入安全点耗时

cleanup: 清理所用时间

vmop: 真正执行VM Operation的时间

可见,那些很多但又很短的安全点,全都是RevokeBias,详见 偏向锁实现原理, 高并发的应用一般会干脆在启动参数里加一句"-XX:-UseBiasedLocking"取消掉它。另外还看到有些类型是no vm operation, 文档上说是保证每秒都有一次进入安全点(如果这秒已经GC过就不用了),给一些需要在安全点里进行,又非紧急的操作使用,比如一些采样型的Profiler工具,可用-DGuaranteedSafepointInterval来调整,不过实际看它并不是每秒都会发生,时间不定。

在实战中,我们利用安全点日志,发现过有程序定时调用Thread Dump等等情况。不过因为安全点日志默认输出到stdout,因为性能及stdout日志的整洁性等原因,我们平时默认没有开启它。只有在需要时才打开。

再再增加下面三个参数,可以知道更多VM里发生的事情。可惜JVM不会因为设了这三个参数,就把安全点日志转移到vm.log里面来,而是白白打印了两次。

-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/dev/shm/vm.log

本文关于快速理解Java垃圾回收和jvm中的stw的介绍就到这里,希望对大家有所帮助,感兴趣的朋友可以参阅:浅谈Java回收对象的标记和对象的二次标记过程 、Java虚拟机装载和初始化一个class类代码解析 、Java中map遍历方式的选择问题详解等,有什么问题可以随时留言,小编会及时回复大家的。

更多精彩内容其他人还在看

Java concurrency之锁_动力节点Java学院整理

这篇文章主要为大家详细介绍了Java concurrency之锁的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Java8新特性之StampedLock_动力节点Java学院整理

本文从synchronized、Lock到Java8新增的StampedLock进行对比分析,对Java8新特性之StampedLock相关知识感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

Java8新特性之lambda的作用_动力节点Java学院整理

我们期待了很久lambda为java带来闭包的概念,但是如果我们不在集合中使用它的话,就损失了很大价值。现有接口迁移成为lambda风格的问题已经通过default methods解决了,在这篇文章将深入解析Java集合里面的批量数据操作解开lambda最强作用的神秘面纱。
收藏 0 赞 0 分享

Java8新特性之Base64详解_动力节点Java学院整理

这篇文章主要为大家详细介绍了Java8新特性之Base64的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Java8新特性之JavaFX 8_动力节点Java学院整理

这篇文章主要介绍了Java8新特性之JavaFX 8的相关知识,非常不错,具有参考借鉴价值,需要的朋友参考下吧
收藏 0 赞 0 分享

将本地jar包安装进入maven仓库(实现方法)

下面小编就为大家带来一篇将本地jar包安装进入maven仓库(实现方法)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

浅谈Java finally语句到底是在return之前还是之后执行(必看篇)

下面小编就为大家带来一篇浅谈Java finally语句到底是在return之前还是之后执行(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

基于Java并发容器ConcurrentHashMap#put方法解析

下面小编就为大家带来一篇基于Java并发容器ConcurrentHashMap#put方法解析。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解Spring Boot Profiles 配置和使用

本篇文章主要介绍了详解Spring Boot Profiles 配置和使用,具有一定的参考价值,有兴趣的可以了解一下
收藏 0 赞 0 分享

详解Spring Boot 属性配置和使用

本篇文章主要介绍了详解Spring Boot 属性配置和使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多