3.1、JVM学习——GC日志含义与配置

本文详细解析了Java虚拟机的GC日志,介绍了如何通过日志了解不同垃圾回收器的工作情况,包括GC日志的组成、关键字含义及通过配置参数指定垃圾回收器的方法。

前言

GC 日志可以提供虚拟机各分代垃圾回收的情况,需要注意的是,不同的垃圾回收器在GC 日志中名字并不相同。

JDK 版本

本文使用 JDK 1.8 x64 进行相关测试

查看垃圾回收器

查看 JVM 垃圾回收器类型的三个方式

测试代码

从实践来说,可以通过限制虚拟机内存大小,然后不断创建对象来触发 GC,也可以直接调用 System.gc(),本文采用了后者——更简单,直观。
当然,作为测试,我们还是增加了一些JVM 的配置参数,用于日志能够展示在控制台上

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728

public class GcTest {
		//-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
		private static final int _1MB = 1024 * 1024;
		private static final int _4MB = 4*1024 * 1024;

		/**
		 * 小对象先保存到 新生代 Eden
		 */
	    public static void testThreshold(){
	        byte[] allocation;
	        allocation = new byte[1 * _1MB];
	    }
	    
	    /**
	     * 大对象直接进入老年代
	     * -XX:PretenureSizeThreshold=3145728
	     */
	    public static void testPretenureSizeThreshold(){
	        byte[] allocation;
	        allocation = new byte[1 * _4MB];
	    }

	    public static void main(String[] args) {
	    	//触发老年代GC
	    	for(int j=0;j<3;j++) {
	    		testPretenureSizeThreshold();
	    	}
	    	
	    	//触发新生代GC
	    	for(int i=0;i<10;i++) {
	    		GcTest.testThreshold();
	    	}
	    	
	    	//手动触发GC
			System.gc();	
	    }
}

控制台内容

控制台内容包含了两个部分,第一个部分是 GC 信息,第二个部分是 Heap 信息
其中 GC 信息就是本文要介绍的GC 日志。
Heap 信息属于PrintGCDetails 的附加信息。

[GC (System.gc()) [PSYoungGen: 1740K->729K(9216K)] 1740K->737K(19456K), 0.0016883 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 729K->0K(9216K)] [ParOldGen: 8K->596K(10240K)] 737K->596K(19456K), [Metaspace: 2677K->2677K(1056768K)], 0.0053865 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 9216K, used 82K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 1% used [0x00000007bf600000,0x00000007bf614920,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 10240K, used 596K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 5% used [0x00000007bec00000,0x00000007bec950e8,0x00000007bf600000)
 Metaspace       used 2684K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

内容解析-GC 信息

[GC (System.gc()) [PSYoungGen: 1740K->729K(9216K)] 1740K->737K(19456K), 0.0016883 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 729K->0K(9216K)] [ParOldGen: 8K->596K(10240K)] 737K->596K(19456K), [Metaspace: 2677K->2677K(1056768K)], 0.0053865 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

GC 日志以是否Stop The World 分为两类

GC 日志可以分为两种,一种是 [GC开头,一种是 [Full GC开头,二者的区别在于,[Full GC表明该垃圾回收过程发生了 Stop The World,需要强调的是,不要将GC 日志中 Full GC 关键字和 老年代的垃圾回收 Full GC 混淆,在GC 日志中 年轻代和老年代的日志是在一起的。

如果垃圾回收是由 Java 代码 System.gc()来触发的,则GC 日志中会增加一个(System.gc()),如本文的 [GC (System.gc()) 和 [Full GC (System.gc())
如果垃圾回收是由于内存空间不够,则会显示分配失败 [GC (Allocation Failure)
此外还会有其他类型的情况

[GC````和``[Full GC中间部分的含义:PsYoungGen 是年轻代的垃圾回收信息
ParOldGen是老年代的垃圾回收信息
Metaspace是元空间的垃圾回收信息
最后一部分 Times 表示垃圾回收期间各部分时间段占用的事件比重

比如 [PSYoungGen: 729K->0K(9216K)]
表示:新生代使用的是 ParallelGC 这种垃圾回收器,新生代总大小为 9216K,垃圾回收前后的内存占用大小为 729K->0K ,即所占用的 729K 空间全部被回收了

不同垃圾回收器日志关键字不同

GC 日志使用不同的关键字来区分不同的垃圾回收期,你应该了解到虚拟机垃圾回收器有多种不同的搭配方式。本文在下面内容中通过不同的VM 配置对不同情况下的GC日志关键字进行归纳总结。

新生代、老年代垃圾回收器的搭配连线图(CMS 是可以和 Serial Old 同时使用的)

在这里插入图片描述

内容解析-Heap 信息

Heap
 PSYoungGen      total 9216K, used 82K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 1% used [0x00000007bf600000,0x00000007bf614920,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 10240K, used 596K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 5% used [0x00000007bec00000,0x00000007bec950e8,0x00000007bf600000)
 Metaspace       used 2684K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

Heap 信息还是很明显的,PSYoungGen 表示年轻代垃圾回收器为 Parallel Scavenge,此外还有年轻代的 eden 、from、to 的信息;ParOldGen 表示老年代垃圾回收器为 Parallel Old,Metaspace 表示元数据信息,
total 表示总大小,used 表示已用

通过 Heap 信息,也可以分辨出来当前所用的是何种垃圾回收器

指定垃圾回收器与GC 关键字

通过参数指定垃圾回收器

参数描述
-XX:+UseSerialGCdef new generation (Serial)
-XX:+UseParNewGCpar new generation
-XX:+UseParallelGCPSYoungGen
-XX:+UseParallelOldGCPSYoungGen
-XX:+UseConcMarkSweepGC (CMS)par new generation

其他参数延伸

直接看 https://blog.youkuaiyun.com/maosijunzi/article/details/46562489

参数类型值举例描述好玩的周边
-Dfile.encoding启动参数=UTF-8影响文件内容,不设定就会采用操作系统的字符集,如果和编译时字符集不一致,就会造成乱码 法国服务器使用中国编译代码出现中文乱码问题
-Dsun.jnu.encoding启动参数=UTF-8影响类名以及输入参数的编码sun.jnu.encoding会影响入参
-Djava.io.tmpdir启动参数/tmp操作系统缓存的临时目录tomcat-临时目录问题
-Djava.net.preferIPv4Stack启动参数false协议栈设置,默认false,为默认值false时,在支持IPv6的双栈系统上,使用Java的Socket会默认通过底层native方法创建一个IPv6 Socket,这个IPv6 Socket可以同时支持和IPv4或IPv6主机通信。如果设置为true,Java程序将无法使用IPv6进行网络通信,也就是仅支持IPv4看下一行
-Djava.net.preferIPv6Addresses启动参数fasle默认false,为默认值false时,IPv4地址会优先使用,例如在DNS通过域名查询IP地址时,会优先使用IPv4地址,反之设为true,则会优先使用IPv6地址Java 设置Ipv4和Ipv6 决定InetAddress.getByName(“www.google.com”),InetAddress.getLocalHost() 返回是否IPV6
-Xss启动参数512K每个线程分配的内存大小栈溢出 StackOverflowError
-Xmx启动参数2g程序运行期间,最大可占用内存This value must a multiple of 1024 greater than 2MB,否则会报 OutOfMemory
-Xms启动参数2g程序启动时占用内存大小,理论上,设置越大,程序启动越快
-XX:MetaspaceSize启动参数256mmatesaceGC发生的初始阈值JVM参数MetaspaceSize的误解
-XX:MaxMetaspaceSiz启动参数256mMeta区容量范围为[20.8m, MaxMetaspaceSize)JVM 元空间扩容和FC的规律
-XX:+AlwaysPreTouch启动参数非赋值配置服务启动的时候真实的分配物理内存给jvm,否则会先配置虚拟内存,实际使用时再配置会降低运行速度,但是配置后启动速度会受影响运行期优化以及G1的特殊问题
-XX:ReservedCodeCacheSize启动参数240m设置codecache的大小,JIT编译后代码临时存储位置,满的话会优化甚至停止JIT,CPU升高,可以用 jconsole 查看codecache 足以引发量级的性能问题
-XX:+HeapDumpOnOutOfMemoryError启动参数非赋值配置JVM发生OOM时,自动生成DUMP文件内存溢出快照查看
-XX:HeapDumpPath启动参数/opt/user/tmp/HeapDump配合 HeapDumpOnOutOfMemoryError 使用,Heap 快照文件的存储位置可以用 jvisulevm 查看 快照文件
-XX:+UseG1GC启动参数非赋值配置使用 G1 GC,全称为 Garbage-First Garbage CollectorG1的一些概念
-XX:G1HeapRegionSize=4M启动参数1M-32M,需为2的幂次方倍,默认2MG1分配内存大小的基本单位G1的young gc\mixed gc\full gc
-XX:InitiatingHeapOccupancyPercent启动参数40,默认45G1 开始并发标记周期时 Perm Gen 占比的阈值,如果设置太大可能导致回收不及时退化为full gc,太小则可能频繁标记G1优化
-XX:MaxGCPauseMillis启动参数100,默认200,单位msGC最大停顿时间不要设置太小,否则会频繁的停顿,造成服务不可用
-XX:+TieredCompilation启动参数非赋值配置分层编译,非赋值配置
-XX:CICompilerCount启动参数4最大并行编译数tomcat 重启负载高问题定位
-XX:-UseBiasedLocking启动参数非赋值配置禁用偏向锁。偏向锁可以提高有同步但没有竞争的程序性能。但是如果锁对象时常被多条线程竞争,那偏向锁就是多余的JVM 偏向锁是如何实现的
-XX:+PrintGCDetails启动参数非赋值配置打印GC详细信息本文有大量GC的例子
-XX:+PrintGCDateStamps启动参数非赋值配置时间格式使用系统时间JVM打印更易读的时间格式
-XX:+PrintGCTimeStamps启动参数非赋值配置JVM自启动到打印日期的时间秒数+PrintGCTimeStamps 展示JVM启动秒数
-XX:+PrintAdaptiveSizePolicy启动参数非赋值配置打印JVM动态调整的各分区大小,ParallelScavenge 会自动调整各分区大小为什么From/To space 大小几乎变成0了呢
-XX:+PrintGCApplicationStoppedTime启动参数非赋值配置打印JVM被停止持续的时间打印GC暂停的时间
-XX:+PrintHeapAtGC启动参数非赋值配置每一次GC后都打印堆信息JVM GC 后打印堆信息
-XX:+PrintStringTableStatistics启动参数非赋值参配置打印字符串常量池统计信息,在GC日志中会多一栏StringTable statistics:字符串常量池日志
-XX:+PrintTenuringDistribution启动参数非赋值配置展示对象晋升到老年代经历GC的次数GC日志打印对象晋升老年代经历GC的次数
-Xloggc启动参数/opt/logs/jvm/gc.logGC日志目录和名称配置GC日志滚动被覆盖问题
-XX:+UseGCLogfileRotation -XX:NumberOfGCLogfiles=N -XX:GCLogfileSize=N符合配置日志循环打印,即产生多个GC日志文件,需要结合下面两个命令使用,即单文件大小,以及循环文件个数,默认文件数为0,大小0 ,即都不做限制,单个GC文件单位为M,建议值为循环30,单个文件30M为什么不推荐使用循环打印日志方式 循环打印GC日志配置
-XX:+PrintFlagsFinal启动参数非赋值配置打印系统所有参数JVM 系统参数查看
-XX:ErrorFile启动参数/opt/logs/jvm/hs_err_pid.logJVM 错误日志JVM参数设置
java_command启动参数./demo.jar使用命令行运行jar
java_class_path启动参数./demo,jar系统类加载器加载字节码class的路径java.class.path详解
11111
-XX:+AlwaysPreTouch运行参数非配置类型服务启动的时候真实的分配物理内存给jvm,会导致启动变慢,

垃圾回收器关键字规律总结

配置年轻代老年代元数据
-XX:+UseSerialGCdef new generationtenured generationMetaspace
-XX:+UseParNewGCpar new generationtenured generationMetaspace
-XX:+UseParallelGCPSYoungGenParOldGenMetaspace
-XX:+UseParallelOldGCPSYoungGenParOldGenMetaspace
-XX:+UseConcMarkSweepGCpar new generationconcurrent mark-sweep generationMetaspace

GC 详情展示

-XX:+UseSerialGC

垃圾回收器: Serial+ SerialOld
GC 日志

[GC (Allocation Failure) [Tenured: 8192K->596K(10240K), 0.0034819 secs] 9932K->596K(19456K), [Metaspace: 2678K->2678K(1056768K)], 0.0035603 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 7331K->0K(9216K), 0.0003829 secs] 12024K->4692K(19456K), 0.0004152 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [Tenured: 4692K->596K(10240K), 0.0031400 secs] 7928K->596K(19456K), [Metaspace: 2678K->2678K(1056768K)], 0.0031873 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

堆信息

 Heap
 def new generation   total 9216K, used 82K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,   1% used [0x00000007bec00000, 0x00000007bec14920, 0x00000007bf400000)
  from space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
  to   space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
 tenured generation   total 10240K, used 596K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
   the space 10240K,   5% used [0x00000007bf600000, 0x00000007bf6950e8, 0x00000007bf695200, 0x00000007c0000000)
 Metaspace       used 2684K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

-XX:+UseParNewGC

垃圾回收器: PawNew+64位时 SerialOld
GC 日志

Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release
[GC (Allocation Failure) [Tenured: 8192K->596K(10240K), 0.0045567 secs] 9932K->596K(19456K), [Metaspace: 2678K->2678K(1056768K)], 0.0046114 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [ParNew: 7331K->0K(9216K), 0.0005674 secs] 12024K->4692K(19456K), 0.0006037 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [Tenured: 4692K->596K(10240K), 0.0024158 secs] 7928K->596K(19456K), [Metaspace: 2678K->2678K(1056768K)], 0.0024644 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 

堆信息

Heap
 par new generation   total 9216K, used 82K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,   1% used [0x00000007bec00000, 0x00000007bec14920, 0x00000007bf400000)
  from space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
  to   space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
 tenured generation   total 10240K, used 596K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
   the space 10240K,   5% used [0x00000007bf600000, 0x00000007bf6950e8, 0x00000007bf695200, 0x00000007c0000000)
 Metaspace       used 2684K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

-XX:+UseParallelGC

垃圾回收器: Parallel Scavenge+Parallel Old
GC 日志

[GC (Allocation Failure) [PSYoungGen: 7884K->745K(9216K)] 16076K->8946K(19456K), 0.0018850 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8077K->681K(9216K)] 16277K->8882K(19456K), 0.0015061 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (System.gc()) [PSYoungGen: 2025K->665K(9216K)] 10225K->8874K(19456K), 0.0010182 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[Full GC (System.gc()) [PSYoungGen: 665K->0K(9216K)] [ParOldGen: 8208K->594K(10240K)] 8874K->594K(19456K), [Metaspace: 2679K->2679K(1056768K)], 0.0052985 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

堆信息

Heap
 PSYoungGen      total 9216K, used 82K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 1% used [0x00000007bf600000,0x00000007bf614920,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 10240K, used 596K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 5% used [0x00000007bec00000,0x00000007bec950e8,0x00000007bf600000)
 Metaspace       used 2683K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

-XX:+UseParallelOldGC

垃圾回收器: Parallel Scavenge+Parallel Old
GC 日志

[GC (Allocation Failure) [PSYoungGen: 7884K->729K(9216K)] 16076K->8930K(19456K), 0.0018887 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8061K->713K(9216K)] 16261K->8914K(19456K), 0.0014337 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (System.gc()) [PSYoungGen: 2057K->633K(9216K)] 10257K->8842K(19456K), 0.0010012 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 633K->0K(9216K)] [ParOldGen: 8208K->594K(10240K)] 8842K->594K(19456K), [Metaspace: 2679K->2679K(1056768K)], 0.0047913 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

堆信息

Heap
 PSYoungGen      total 9216K, used 82K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 1% used [0x00000007bf600000,0x00000007bf614920,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 10240K, used 596K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 5% used [0x00000007bec00000,0x00000007bec950e8,0x00000007bf600000)
 Metaspace       used 2684K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K

-XX:+UseConcMarkSweepGC

垃圾回收器: ParNew+CMS
GC 日志

[GC (Allocation Failure) [CMS: 8192K->600K(10240K), 0.0039740 secs] 9932K->600K(19456K), [Metaspace: 2677K->2677K(1056768K)], 0.0040636 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 7331K->0K(9216K), 0.0005220 secs] 12028K->4696K(19456K), 0.0005620 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [CMS: 4696K->599K(10240K), 0.0022873 secs] 7932K->599K(19456K), [Metaspace: 2678K->2678K(1056768K)], 0.0023498 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

堆信息

Heap
 par new generation   total 9216K, used 82K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,   1% used [0x00000007bec00000, 0x00000007bec14920, 0x00000007bf400000)
  from space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
  to   space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
 concurrent mark-sweep generation total 10240K, used 600K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 2683K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 288K, capacity 386K, committed 512K, reserved 1048576K
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值