虚拟机日志

打印GC日志可以使用参数-XX:+PrintGC

/**
* -Xmx10m -Xms10m -XX:PretenureSizeThreshold=10485760
* -XX:+PrintGC -XX:+UseSerialGC
*/
public class GCLogTest { private static final int CAPACITY = 6*1024*1024; public static void main(String[] args) { byte[] a1 = new byte[CAPACITY];
a1 = null;
System.out.println("1111"); byte[] a2 = new byte[CAPACITY];
a2 = null;
System.out.println("2222"); byte[] a3 = new byte[CAPACITY];
System.out.println("3333");
}
}
1111
[GC (Allocation Failure) 7004K->6676K(9920K), 0.0011969 secs]
[Full GC (Allocation Failure) 6676K->531K(9920K), 0.0014471 secs]
2222
[GC (Allocation Failure) 6730K->6675K(9920K), 0.0001418 secs]
[Full GC (Allocation Failure) 6675K->531K(9920K), 0.0010813 secs]
3333

如果需要更详细的信息,可以使用-XX:+PrintGCDetails

1111
[GC (Allocation Failure) [DefNew: 809K->320K(3072K), 0.0012200 secs][Tenured: 6353K->528K(6848K), 0.0012924 secs] 6953K->528K(9920K), [Metaspace: 2645K->2645K(1056768K)], 0.0025600 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2222
[GC (Allocation Failure) [DefNew: 55K->0K(3072K), 0.0002147 secs][Tenured: 6672K->528K(6848K), 0.0011609 secs] 6727K->528K(9920K), [Metaspace: 2645K->2645K(1056768K)], 0.0014129 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
3333

以上面的第一次GC进行分析,GC日志开头的“GC”,说明这次垃圾回收的停顿类型。一般还有Full GC (System.gc()) 和Full GC,前者说明是调用System.gc()触发,后者一般是分配担保失败的原因。而a1变量所占用内存是6M,结合GC日志新生代占用809k,老年代占用6353k,可以推断出是内存直接分配在老年代的。《深入理解Java虚拟机》中内存分配和回收策略中有“大对象直接进入老年代”。所谓的大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是很长的字符串及数组。

接下来DefNew、Tenured、Metaspace(使用的是JDK1.8,在该版本之下是Perm)表示GC发生的区域,这里显示的区域名和具体使用的垃圾回收器密切相关。如DefNew(Default New Generation),说明使用时Serial收集器,刚好使用-XX:+UseSerialGC参数。如果是ParNew收集器,新生代名称是ParNew(Parallel New Generation),如果采用Parallel Scavenge收集器,它的新生代名称是PSYoungGen。老年代和永久代同理。

“809K->320K(3072K), 0.0012200 secs”表示“新生代GC前使用的内存->新生代GC后使用的内存(新生代的可使用总内存(eden+from内存),此次GC占用时间”。“6353K->528K(6848K)”表示“老年代GC前使用的内存->老年代GC后使用的内存(老年代的总内存)”。“6953K->528K(9920K)”表示“GC前堆使用的内存->GC后堆使用的内存(堆的总内存)”。3072加6848刚好等于9920。

堆参数配置

堆内存是Java进程的重要组成部分,几乎所有与应用相关的内存空间都和堆有关。堆的相关参数可以说是Java虚拟机中最重要的,也对程序的性能有着重要的影响,而且内存溢出最常见的就是发生在堆中。

最大堆和堆初始配置

当虚拟机启动,虚拟机就会初始化堆空间,可以使用-Xms来指定。一般来说虚拟机会尽可能维持在初始堆空间的范围内运行。但是如果初始堆空间耗尽,虚拟机会对空间进行扩展,其上限为最堆对空间,由-Xmx参数来指定。

	private static final int CAPACITY = 6*1024*1024;

	/**
* -Xms10m
*/
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().totalMemory()+" bytes");
byte[] a1 = new byte[CAPACITY];
byte[] a2 = new byte[CAPACITY];
System.out.println(Runtime.getRuntime().totalMemory()+" bytes"); }

结果如下,说明了虚拟机对堆内存进行了扩展

9961472 bytes
16777216 bytes

在实际项目中,可以将-Xms和-Xmx设置相等,这样的好处是可以减少程序运行时进行的垃圾回收次数,从而提高性能

新生代配置

参数-Xmn可以用于设置新生代的大小,那么老年代的大小就是-Xms减去-Xmn的值。新生代的值一般设置在整个堆空间的1/4到1/3左右。除了可以用-Xmn指定新生代的绝对大小,还可以使用-XX:NewRatio来设置新生代和老年代的比例。-XX:NewRatio=老年代/新生代

参数-XX:SurvivorRatio用于设置新生代中eden空间和from/to空间的比例。它的含义是:-XX:SurvivorRatio=eden/from=eden/to。如下代码可以观察不同的参数对GC影响

/**
* 默认VM参数:-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* 修改 -Xmn参数
*/
public static void main(String[] args) {
byte[] a = null;
for(int i=0; i<10; i++) {
a = new byte[1024*1024];
}
}
  1. -Xmn1m时,GC日志如下。eden区为1M*(2/(2+2))=0.5M,from=to=0.25M,新生代可使用内存eden + from=768K(如下total 768K)。eden区无法容纳1M的数据,所以触发了一次新生代的GC,GC后还是无法容纳1M数据,导致数据最终都分配在老年代,老年代最终占用10413K。
	[GC (Allocation Failure) [DefNew: 507K->256K(768K), 0.0009151 secs] 507K->428K(20224K), 0.0009609 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 768K, used 514K [0x00000000fec00000, 0x00000000fed00000, 0x00000000fed00000)
eden space 512K, 50% used [0x00000000fec00000, 0x00000000fec40b40, 0x00000000fec80000)
from space 256K, 100% used [0x00000000fecc0000, 0x00000000fed00000, 0x00000000fed00000)
to space 256K, 0% used [0x00000000fec80000, 0x00000000fec80000, 0x00000000fecc0000)
tenured generation total 19456K, used 10413K [0x00000000fed00000, 0x0000000100000000, 0x0000000100000000)
the space 19456K, 53% used [0x00000000fed00000, 0x00000000ff72b448, 0x00000000ff72b600, 0x0000000100000000)
Metaspace used 2686K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 286K, capacity 386K, committed 512K, reserved 1048576K
  1. -Xmn7m时,GC日志如下。eden=3.5M=3584K,from=to=1792K,新生代可以内存5376K。当初始化第三个数组前的时候时,eden区已经使用2886K,还剩下692K(3584-2886),明显不够分配,触发一次Minor GC。接下来初始化到第六个数组前时,eden区已使用3142K(4695-1553),还剩下442K(3584-3142),也要触发Minor GC。
[GC (Allocation Failure) [DefNew: 2886K->1553K(5376K), 0.0013204 secs] 2886K->1553K(18688K), 0.0013493 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4695K->1024K(5376K), 0.0010302 secs] 4695K->1552K(18688K), 0.0010404 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 4157K->1024K(5376K), 0.0002867 secs] 4686K->1552K(18688K), 0.0002951 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 5376K, used 3208K [0x00000000fec00000, 0x00000000ff300000, 0x00000000ff300000)
eden space 3584K, 60% used [0x00000000fec00000, 0x00000000fee223a0, 0x00000000fef80000)
from space 1792K, 57% used [0x00000000ff140000, 0x00000000ff240010, 0x00000000ff300000)
to space 1792K, 0% used [0x00000000fef80000, 0x00000000fef80000, 0x00000000ff140000)
tenured generation total 13312K, used 528K [0x00000000ff300000, 0x0000000100000000, 0x0000000100000000)
the space 13312K, 3% used [0x00000000ff300000, 0x00000000ff384148, 0x00000000ff384200, 0x0000000100000000)
Metaspace used 2651K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 285K, capacity 386K, committed 512K, reserved 1048576K

非堆参数配置

除了堆内存,虚拟机还有一些内存用于方法区、栈和直接内存的使用。和堆内存相比,这些内存空间和应用程序的关系不那么密切,但是合理的配置也对系统的性能和稳定有着重要的作用。

方法区配置

方法区主要存放类的元数据信息。在JDK1.6和JDK1.7的版本中,可以使用-XX:PermSize和-XX:MaxPermSize配置永久代大小。在JDK1.8中,永久代被彻底移除,使用心得元数据区存放类的元数据。默认情况元数据区只接受系统的可用内存限制,但是依然可以是参数-XX:MaxMetaspaceSize指定元数据区大小。

栈配置配置

栈是每个线程的私有空间,在虚拟机中可以用-Xss参数来指定线程栈的大小。

public class StackDeepTest {

    private static int count = 0;

    public static void recursionCall() {
count ++;
recursionCall();
} public static void main(String[] args) {
try {
recursionCall();
}catch(Throwable ex) {
System.out.println("调用了:"+count);
ex.printStackTrace();
}
}
}

使用-Xss128k参数,结果为“调用了:1089”,当使用-Xss256k参数,结果为“调用了:3546”。说明参数改大之后调用的次数能够明显增加。

直接内存配置

堆外内存,又被称为直接内存。这部分内存不是由jvm管理和回收的。需要我们手动的回收。堆内内存是属于jvm的,由jvm进行分配和管理,属于"用户态",而推外内存是由操作系统管理的,属于"内核态"在jdk1.4中新加入了NIO类,可以调用ByteBuffer.allocateDirect()方法来分配直接内存。可以通过-XX:MaxDirectMemorySize参数来指定最大直接内存。

/**
* -Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* -XX:MaxDirectMemorySize=9437184=9M
*/
public static void main(String[] args) {
ByteBuffer.allocateDirect(1024*1024*10);
}

直接内存达到上限时,会触发垃圾回收(JDK自己调用System.gc(),所以不建议关闭-XX:+DisableExplicit,禁止代码中显示调用gc(System.gc),如果溢出,也会抛出OOM异常,如下所示。

[Full GC (System.gc()) [Tenured: 0K->528K(13312K), 0.0023684 secs] 838K->528K(18688K), [Metaspace: 2645K->2645K(1056768K)], 0.0024284 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at dd.GCLogTest.main(GCLogTest.java:16)

虚拟机参数

查看虚拟的所有参数-XX:+PrintFlagsFinal

行为参数:

参数及其默认值 描述
-XX:-DisableExplicitGC 禁止调用System.gc();但jvm的gc仍然有效
-XX:+MaxFDLimit 最大化文件描述符的数量限制
-XX:+ScavengeBeforeFullGC 新生代GC优先于Full GC执行
-XX:+UseGCOverheadLimit 在抛出OOM之前限制jvm耗费在GC上的时间比例
-XX:-UseConcMarkSweepGC 对老生代采用并发标记交换算法进行GC
-XX:-UseParallelGC 启用并行GC,收集新生代空间
-XX:-UseParallelOldGC 对Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用
-XX:-UseSerialGC 启用串行GC
-XX:+UseThreadPriorities 启用本地线程优先级

性能调优参数列表:

参数及其默认值 描述
-XX:LargePageSizeInBytes=4m 设置用于Java堆的大页面尺寸
-XX:MaxHeapFreeRatio=70 GC后java堆中空闲量占的最大比例
-XX:MaxNewSize=size 新生成对象能占用内存的最大值
-XX:MaxPermSize=64m 老生代对象能占用内存的最大值
-XX:MinHeapFreeRatio=40 GC后java堆中空闲量占的最小比例
-XX:NewRatio=2 新生代内存容量与老生代内存容量的比例
-XX:NewSize=2.125m 新生代对象生成时占用内存的默认值
-XX:ReservedCodeCacheSize=32m 保留代码占用的内存容量
-XX:ThreadStackSize=512 设置线程栈大小,若为0则使用系统默认值
-XX:+UseLargePages 使用大页面内存

调试参数列表:

参数及其默认值 描述
-XX:-CITime 打印消耗在JIT编译的时间
-XX:ErrorFile=./hs_err_pid.log 保存错误日志或者数据到文件中
-XX:-ExtendedDTraceProbes 开启solaris特有的dtrace探针
-XX:HeapDumpPath=./java_pid.hprof 指定导出堆信息时的路径或文件名
-XX:-HeapDumpOnOutOfMemoryError 当首次遭遇OOM时导出此时堆中相关信息
-XX: 出现致命ERROR之后运行自定义命令
-XX:OnOutOfMemoryError=";" 当首次遭遇OOM时执行自定义命令
-XX:-PrintClassHistogram 遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同
-XX:-PrintConcurrentLocks 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同
-XX:-PrintCommandLineFlags 打印在命令行中出现过的标记
-XX:-PrintCompilation 当一个方法被编译时打印相关信息
-XX:-PrintGC 每次GC时打印相关信息
-XX:-PrintGC Details 每次GC时打印详细信息
-XX:-PrintGCTimeStamps 打印每次GC的时间戳
-XX:-TraceClassLoading 跟踪类的加载信息
-XX:-TraceClassLoadingPreorder 跟踪被引用到的所有类的加载信息
-XX:-TraceClassResolution 跟踪常量池
-XX:-TraceClassUnloading 跟踪类的卸载信息
-XX:-TraceLoaderConstraints 跟踪类加载器约束的相关信息

Java虚拟机日志与参数的更多相关文章

  1. Java虚拟机-JVM各种参数配置大全详细

      usr/local/jdk/bin/java -Dresin.home=/usr/local/resin -server -Xms1800M -Xmx1800M -Xmn300M -Xss512K ...

  2. Java虚拟机--------JVM常见参数

    JVM 调优常见参数 Java1.7的jvm参数查看一下官方网站. http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java. ...

  3. 了解java虚拟机—JVM相关参数设置(2)

    1.   JVM相关参数设置 JVM相关配置 -XX:+PrintGC 两次次YoungGC,两次FullGC. -XX:+PrintGCDetails 打印GC时的内存,并且在程序结束时打印堆内存使 ...

  4. 了解java虚拟机—堆相关参数设置(3)

    堆相关配置 -Xmx 最大堆空间 -Xms 初始堆空间大小,如果初始堆空间耗尽,JVM会对堆空间扩容,其扩展上限为最大堆空间.通常-Xms与-Xmx设置为同样大小,避免扩容造成性能损耗. -Xmn 设 ...

  5. 深入JVM-常用Java虚拟机参数

    一.跟踪调试参数 1.1 跟踪垃圾回收-读懂虚拟机日志 Java的一大特色就是支持自动的垃圾回收(GC),但是有时候,如果垃圾回收频繁出现,或者占用了太长的CPU时间,就不得不引起重视.此时,就需要一 ...

  6. Java虚拟机参数,增加虚拟机最大内存,在/etc/profile增加如下: export JAVA_OPTS="-Xms9g -Xmx9g"

    一.运行class文件 执行带main方法的class文件,Java虚拟机命令参数行为: java <CLASS文件名> 注意:CLASS文件名不要带文件后缀.class 例如: java ...

  7. java虚拟机的原理

    所谓虚拟机,就是一台虚拟的机器.它是一款软件,用来执行一系列虚拟计算机指令,大体上虚拟机可以分为系统虚拟机和程序虚拟机,Visual Box .Vmare就属于系统虚拟机.他们完全是对物理计算机的仿真 ...

  8. Java虚拟机三 Java堆和栈

    Java堆是和Java应用程序关系最为紧密的内存空间,几乎所有的对象都存放在堆中.并且堆是完全自动化管理的. 根据垃圾回收机制的不同,Java堆有可能有不同的结构.最为常见的一种就是将整个Java堆分 ...

  9. 实战Java虚拟机之一“堆溢出处理”

    从今天开始,我会发5个关于java虚拟机的小系列: 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Java虚拟机之四 ...

随机推荐

  1. infiniband install driver

    硬件:Mellanox InfiniBand,主要包括 HCA(主机通道适配器)和交换机两部分 软件:CentOS 6.4 MLNX_OFED_LINUX-2.1-1.0.0-rhel6.4-x86_ ...

  2. ZIP:ZipEntry

    ZipEntry: /* 此类用于表示 ZIP 文件条目. */ ZipEntry(String name) :使用指定名称创建新的 ZIP 条目. ZipEntry(ZipEntry e) :使用从 ...

  3. list和list<map<String,object>>比较,不存在map的key赋值

    package com; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDa ...

  4. ‎Cocos2d-x 3.x 学习笔记(三):Scheduler Timer 调度与定时

    ‎1. 概述 Cocos2d-x 的 Scheduler 离不开 Timer.Timer 类是定时器,用来规定一个回调函数应该在何时被触发.Timer 封装了已运行时间.重复次数.已执行次数.延迟秒数 ...

  5. Spring Bean 的装配方式

    Spring Bean 的装配方式 装配 Bean 的三种方式 一个程序中,许多功能模块都是由多个为了实现相同业务而相互协作的组件构成的.而代码之间的相互联系又势必会带来耦合.耦合是个具有两面性的概念 ...

  6. 基于TCP协议的套接字编程

    06.26自我总结 1.关于Socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在 ...

  7. apache添加https证书

    今天折腾了一下,总结apache添加https证书的方法. 证书类型分为两种, A)自签名证书 利用oepnssl命令生成.csr和key文件,没有授信,没有有效期,但是可以强制使用https协议,可 ...

  8. 《VR入门系列教程》之11---基本几何-材质-光照

    网格.多边形.顶点     绘制3D图形有许多方法,用的最多的是用网格绘制.一个网格由一个或多个多边形组成,这些多边形的顶点都是三维空间中的点,它们具有x.y.z三个坐标值.网格中通常采用三角形和四边 ...

  9. python 爬取豆瓣电影评论,并进行词云展示及出现的问题解决办法

    本文旨在提供爬取豆瓣电影<我不是药神>评论和词云展示的代码样例 1.分析URL 2.爬取前10页评论 3.进行词云展示 1.分析URL 我不是药神 短评 第一页url https://mo ...

  10. C++ protobuffer 前后端通信 简单应用

    后端发送多个protobuffer消息到前端,前端用socket监听,如何区分消息类型呢? //定义心跳包 DseHeartbeat _DseHeartbeat; DseHeartbeat _DseH ...