JVM GC中Stop the world案例实战

原创 2016年08月31日 00:00:34

GC中Stop the world案例实战

为了更好的理解GC中的Stop the world案例,就必须先了解何为Stop the World方式。所谓的Stop the World机制,简称STW,即在执行垃圾收集算法时,Java应用程序的其他所有除了垃圾收集收集器线程之外的线程都被挂起(具体运行机制见图4-1)。此时,系统只能允许GC线程进行运行,其他线程则会全部暂停,等待GC线程执行完毕后才能再次运行。这些工作都是由虚拟机在后台自动发起和自动完成的,是在用户不可见的情况下把用户正常工作的线程全部停下来,这对于很多的应用程序,尤其是那些对于实时性要求很高的程序来说是难以接受的。但是有些时候对于虚拟机来说采用Stop the world机制是无法避免的,例如采用复制算法时,为了保证在复制存活的对象的时候,对象的一致性,不然要使应用程序被挂起。但是随着java虚拟机的发展,HotSpot虚拟机团队为达到更好用户体验而一直进行着努力,不断的对垃圾收集器进行着改进,随着JDK的版本的不断更新,更好的垃圾收集器的出现,用户线程的停顿时间也在不断缩短,虽然这一时间现阶段仍然不能消除,但相信不久的未来一定会有更好的垃圾收集器被发现,从而完全达到用户对于虚拟机垃圾回收的性能要求。


图4-1Stop the World机制的GC

         对于很多的垃圾收集器来说,都会采用Stop the World机制来进行垃圾回收。具体来讲,在Java虚拟机的Serial, ParNew, Parallel Scanvange, ParallelOld, Serial Old全程都会Stop the world,JVM这时候只运行GC线程,不运行用户线程。而CMS主要分为 initial Mark, Concurrent Mark, ReMark,Concurrent Sweep等阶段,initial Mark和Remark占整体的时间比较较小,它们会Stop the world. Concurrent Mark和Concurrent Sweep会和用户线程一起运行。虽然CMS减少了stop the world的次数,不可避免地让整体GC的时间拉长了。各个垃圾收集器GC采用的方式见图4-2。

                                               

图4-2各个垃圾收集器GC采用的方式

 

了解了Stop the world机制,接下来将展示一个案例来讲解GC中Stop the World机制具体的运行机制,让读者有一个更直观的印象。

/**
*案例4.1 测试的SWT机制的GC
**/
package ErrorType;
import java.util.ArrayList;
import java.util.List;
/**
*
**/
class Person{ 
	private String name;
	private String age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
}

public class Test {
	public static void main(String[] args) {
		List<Person> persons = new ArrayList<Person>();
		long start = 0L;
		long end = 0L;
		long runtime = 0L;
		int count = 0;
		while(true) {
			start = System.currentTimeMillis();
			persons.add(new Person());
			count++;
			end = System.currentTimeMillis();
			runtime = end - start;
			System.out.println(count + " : Use time in one operation:" + runtime + "ms");
			start = end;
		}
	}

}

Eclipse参数设置:

-Xms100M -Xmx100M -Xss128k -XX:+PrintGCDetails 
-XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:./gclogs

参数解释:

-Xms和-Xmx分别设置了堆的初始大小为10M和最大大小也为10M,这两个参数一般配合使用,且设置为同一值。-Xss参数设定了每个线程堆栈大小为128k  -XX:+PrintGCDetails 表示打印GC的信息,这里通过-Xloggc:./gclogs将GC信息输出到gclogs文件中。-XX:+PrintGCDateStamps则表示在GC信息里显示当前时间。-XX:+PrintHeapAtGC表示在每次GC前显示当前堆中的状态。

这里截取部分输出:

38503 : Use time in one operation:0ms
38504 : Use time in one operation:0ms
38505 : Use time in one operation:1ms
38506 : Use time in one operation:0ms
38507 : Use time in one operation:0ms
38508 : Use time in one operation:0ms
38509 : Use time in one operation:0ms

可以看出,正常进行一次persons.add(newPerson())操作耗时是不到1ms的,但是在将第38505个对象进行persons.add(new Person())操作时,耗时将达到1ms,这说明这时系统进行了GC,且使用了STW机制。

另一方面,从GC日志文件gclogs中,可以看到如下内容:

Java HotSpot(TM) 64-Bit Server VM (25.73-b02) for windows-amd64 JRE (1.8.0_73-b02), built on Jan 29 2016 17:38:49 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 12034908k(8867180k free), swap 13345628k(8226180k free)
CommandLine flags: -XX:InitialHeapSize=104857600 -XX:MaxHeapSize=104857600 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:SurvivorRatio=1 -XX:ThreadStackSize=128 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 22528K, used 11264K [0x00000000fdf00000, 0x0000000100000000, 0x0000000100000000)
  eden space 11264K, 100% used [0x00000000fdf00000,0x00000000fea00000,0x00000000fea00000)
  from space 11264K, 0% used [0x00000000ff500000,0x00000000ff500000,0x0000000100000000)
  to   space 11264K, 0% used [0x00000000fea00000,0x00000000fea00000,0x00000000ff500000)
 ParOldGen       total 68608K, used 0K [0x00000000f9c00000, 0x00000000fdf00000, 0x00000000fdf00000)
  object space 68608K, 0% used [0x00000000f9c00000,0x00000000f9c00000,0x00000000fdf00000)
 Metaspace       used 2750K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 301K, capacity 386K, committed 512K, reserved 1048576K
2016-05-15T12:59:45.962+0800: 0.988: [GC (Allocation Failure) [PSYoungGen: 11264K->1226K(22528K)] 11264K->1234K(91136K), 0.0047652 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

可以看到在GC前,新生代eden区域使用已经达到100%,从而导致新对象的内存分配失败引发了Minor GC,日志里显示了PSYoungGen、ParOldGen以及Metaspace等区域的使用情况,这里不做详细解释。

下面,主要讲解下最后的GC输出信息。

         YGC发生于2016-05-15T12:59:45.962+0800,YGC前新生代占用大小为11264K,约为12M,YGC后新生代占用内存大小为1226K,约为1M,而新生代总大小为22528K,约为22M。YGC前JVM堆内存占用为11264K,YGC后堆内存占用为1234K,JVM对总大小为91136K,约91M。期间用户态耗时小于0.01s,内核态耗时小于0.01s,实际耗时为0.01s。

         同样JVM中给开发者提供了一个参数,-XX:+PrintGCApplicationStoppedTime,来显示应用程序在Java虚拟机进行所有GC暂停的总耗时。

         到这里,STW的例子就讲完了,相信对着对GC过程又有了新一层的认识了。


版权声明:本文为博主原创文章,转载时请标明出处。

Java垃圾回收中Stop-The-World和JVM中的Stop-The-World

Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停...
  • b_11111
  • b_11111
  • 2016年10月02日 22:34
  • 2621

设计模式(六)代理模式

代理模式也叫委托模式,是结构型设计模式的一种。在现实生活中我们用到类似代理模式的场景有很多,比如代购、代理上网、打官司等。...

Android中子线程和UI线程之间通信的方式(Handler与Thread-附源码)

Android中子线程和UI线程之间通信的详细解释 1.在多线程编程这块,我们经常要使用Handler,Thread和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢?下面详解一下。 ...

[Java JVM] Hotspot GC研究- GC安全点 (Safepoint&Stop The World)

什么是safepoint引用openjdk官网的一段话: A point during program execution at which all GC roots are known and ...
  • lqp276
  • lqp276
  • 2016年08月19日 11:56
  • 1354

Java 内存区域和GC机制以及JVM(Java虚拟机)优化大全和案例实战

目录 Java垃圾回收概况Java内存区域Java对象的访问方式Java内存分配机制Java GC机制垃圾收集器 Java垃圾回收概况   Java GC(Garbage Collection,...

Sapphire算法:GC Without Stop the World(上)

Go的GC一致为人诟病,然而Go1.5据说大大优化了GC,具体可以见这篇文章http://www.oschina.net/translate/go-gc-solving-the-latency-pro...
  • InsZVA
  • InsZVA
  • 2016年03月02日 14:18
  • 1176

JVM进阶(八)——Stop The World

JVM进阶(八)——Stop The World  小伙伴还记得上一篇中我们留下的一个问题吗?什么是停顿类型!经过前几章的学习,我们知道垃圾回收首先是要经过标记的。对象被标记后就会根据不同的区域采用不...

jvm 性能调优案例和GC 垃圾回收器详细说明。

1:新生代串行收集器:(默认收集器)      算法:复制算法      -XX:+UseSerialGC 指定使用新生代串行收集器和老年代串行收集器      优点:效率高,久经考验   ...

JVM-GC总结-配置实战--第三发

配置举例1:vm args: -Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=3 -XX:MaxPermSize=30m -XX:MaxTenur...

JVM GC一次调优实战

 CMS的Full GC采用压缩式垃圾收集,在堆比较大的时候,如果full gc频繁,会导致停顿,并且调用方阻塞、超时、甚至雪崩的情况出现,所以降低full gc的发生频率和需要时间,非常有必要...
  • xpb1980
  • xpb1980
  • 2016年06月24日 10:46
  • 612
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JVM GC中Stop the world案例实战
举报原因:
原因补充:

(最多只允许输入30个字)