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

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遍历方式的选择问题详解等,有什么问题可以随时留言,小编会及时回复大家的。

(0)

相关推荐

  • 从JVM的内存管理角度分析Java的GC垃圾回收机制

    一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率 ,才能提高整个应用程序的性能.本篇文章首先简单介绍GC的工作原理之后,然后再对GC的几个关键问题进行深入探讨,最后提出一些Java程序设计建议,从GC角度提高Java程序的性能.     GC的基本原理     Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放.     对于程序员来说,分配对象使用

  • 从JVM分析Java的类的加载和卸载机制

    类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构. 加载.class文件的方式: 1.从本地系统中直接加载 2.通过网络下载.class文件 3.从zip,jar等归档文件中加载.class文件 4.从专有数据库中提取.class文件 5.将Java源文件动态编译为.class文件 类的加载的最终产品是位于堆区中的Class对象. Class对象封装了类在

  • 在java代码中获取JVM参数的方法

    实例如下: MemoryMXBean memorymbean = ManagementFactory.getMemoryMXBean(); MemoryUsage usage = memorymbean.getHeapMemoryUsage(); System.out.println("INIT HEAP: " + usage.getInit()); System.out.println("MAX HEAP: " + usage.getMax()); System.

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

    Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外).Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互:这些现象多半是由于gc引起. GC时的Stop the World(STW)是大家最大的敌人.但可能很多人还不清楚,除了GC,JVM下还会发生停顿现象. JVM里有一条特殊的线程--VM Threads,专门用来执行一些特殊的VM Operation

  • 深入理解Java垃圾回收机制以及内存泄漏

    前言 在segmentfault上看到一个问题:java有完善的GC机制,那么在java中是否会出现内存泄漏的问题,以及能否给出一个内存泄漏的案例.本问题视图给出此问题的完整答案. 垃圾回收机制简介 在程序运行过程中,每创建一个对象都会被分配一定的内存用以存储对象数据.如果只是不停的分配内存,那么程序迟早面临内存不足的问题.所以在任何语言中,都会有一个内存回收机制来释放过期对象的内存,以保证内存能够被重复利用. 内存回收机制按照实现角色的不同可以分为两种,一种是程序员手动实现内存的释放(比如C语

  • 快速了解JAVA垃圾回收机制

    说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理.顾名思义,垃圾回收就是释放垃圾占用的空间,那么在Java中,什么样的对象会被认定为"垃圾"?那么当一些对象被确定为垃圾之后,采用什么样的策略来进行回收(释放空间)?在目前的商业虚拟机中,有哪些典型的垃圾收集器?下面我们就来逐一探讨这些问题.以下是本文的目录大纲: 如果有不正之处,希望谅解和批评指

  • 理解Java垃圾回收

    当程序创建对象.数组等引用类型的实体时,系统会在堆内存中为这一对象分配一块内存,对象就保存在这块内存中,当这块内存不再被任何引用变量引用时,这块内存就变成垃圾,等待垃圾回收机制进行回收.垃圾回收机制具有三个特征: 垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(例如数据库连接,打开的文件资源等),也不会回收以某种创建对象的方式以外的方式为该对像分配的内存,(例如对象调用本地方法中malloc的方式申请的内存) 程序无法精确控制垃圾回收的运行,只可以建议垃圾回收进行,建议的方式有两种S

  • Java垃圾回收机制简述

    说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理. 顾名思义,垃圾回收就是释放垃圾占用的空间,那么在Java中,什么样的对象会被认定为"垃圾"?那么当一些对象被确定为垃圾之后,采用什么样的策略来进行回收(释放空间)?在目前的商业虚拟机中,有哪些典型的垃圾收集器?下面我们就来逐一探讨这些问题.以下是本文的目录大纲: 如何确定某个对象是"

  • 快速理解Java设计模式中的组合模式

    组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 通用类图如下: 组合模式的包含角色: ● Component 抽象构件角色 定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. ● Leaf 叶子构件 叶子对象,其下再也没有其他的分支,也就是遍历的最

  • 浅谈Java垃圾回收的实现过程

    本教程是为了理解基本的Java垃圾回收以及它是如何工作的.这是垃圾回收教程系列的第二部分.希望你已经读过了第一部分:<简单介绍Java垃圾回收机制>. Java垃圾回收是一项自动化的过程,用来管理程序所使用的运行时内存.通过这一自动化过程,JVM解除了程序员在程序中分配和释放内存资源的开销. 启动Java垃圾回收 作为一个自动的过程,程序员不需要在代码中显示地启动垃圾回收过程.System.gc()和Runtime.gc()用来请求JVM启动垃圾回收. 虽然这个请求机制提供给程序员一个启动GC

  • 关于Java垃圾回收开销降低的几条建议

    保持GC低开销的窍门有哪些? 随着一再拖延而即将发布的 Java9,G1("Garbage First")垃圾回收器将被成为 HotSpot 虚拟机默认的垃圾回收器.从 serial 垃圾回收器到CMS 收集器, JVM 见证了许多 GC 实现,而 G1 将成为其下一代垃圾回收器. 随着垃圾收集器的发展,每一代 GC 与其上一代相比,都带来了巨大的进步和改善.parallel GC 与 serial GC 相比,它让垃圾收集器以多线程的方式工作,充分利用了多核计算机的计算能力.CMS(

  • 简单介绍Java垃圾回收机制

    Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序. 这篇教程是系列第一部分.首先会解释基本的术语,比如JDK.JVM.JRE和HotSpotVM.接着会介绍JVM结构和Java堆内存结构.理解这些基础对于理解后面的垃圾回收知识很重要. Java关键术语 JavaAPI:一系列帮助开发者创建Java应用程序的封装好的库. Java开发工具包(JDK):一

  • Java垃圾回收之分代收集算法详解

    概述 这种算法,根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法.可以用抓重点的思路来理解这个算法. 新生代对象朝生夕死,对象数量多,只要重点扫描这个区域,那么就可以大大提高垃圾收集的效率.另外老年代对象存储久,无需经常扫描老年代,避免扫描导致的开销. 新生代 在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集:可以参看我之前写的Java垃圾回收之复制算法详解 老年代

随机推荐