Java虚拟机详解----常用JVM配置参数


【声明】 

欢迎转载,但请保留文章原始出处→_→ 

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:http://www.cnblogs.com/smyhvae/p/4736162.html

联系方式:smyhvae@163.com  

 

本文主要内容:

  • Trace跟踪参数
  • 堆的分配参数
  • 栈的分配参数

 

零、在IDE的后台打印GC日志:

既然学习JVM,阅读GC日志是处理Java虚拟机内存问题的基础技能,它只是一些人为确定的规则,没有太多技术含量。

既然如此,那么在IDE的控制台打印GC日志是必不可少的了。现在就告诉你怎么打印。

(1)如果你用的是Eclipse,打印GC日志的操作如下:



在上图的箭头处加上-XX:+PrintGCDetails这句话。于是,运行程序后,GC日志就可以打印出来了:


(2)如果你用的是IntelliJ IDEA,打印GC日志的操作如下:



在上图的箭头处加上-XX:+PrintGCDetails这句话。于是,运行程序后,GC日志就可以打印出来了:


当然了,光有-XX:+PrintGCDetails这一句参数肯定是不够的,下面我们详细介绍一下更多的参数配置。

 

一、Trace跟踪参数:

1、打印GC的简要信息:

-verbose:gc
-XX:+printGC

解释:可以打印GC的简要信息。比如:

[GC 4790K->374K(15872K), 0.0001606 secs]

[GC 4790K->374K(15872K), 0.0001474 secs]

[GC 4790K->374K(15872K), 0.0001563 secs]

[GC 4790K->374K(15872K), 0.0001682 secs]

上方日志的意思是说,GC之前,用了4M左右的内存,GC之后,用了374K内存,一共回收了将近4M。内存大小一共是16M左右。

 

2、打印GC的详细信息:

-XX:+PrintGCDetails

解释:打印GC详细信息。

-XX:+PrintGCTimeStamps

解释:打印CG发生的时间戳。

 

理解GC日志的含义:

例如下面这段日志:

[GC[DefNew: 4416K->0K(4928K), 0.0001897 secs] 4790K->374K(15872K), 0.0002232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

上方日志的意思是说:这是一个新生代的GC。方括号内部的“4416K->0K(4928K)”含义是:“GC前该内存区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)”。而在方括号之外的“4790K->374K(15872K)”表示“GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)”。

再往后看,“0.0001897 secs”表示该内存区域GC所占用的时间,单位是秒。

 

再比如下面这段GC日志:


上图中,我们先看一下用红框标注的“[0x27e80000, 0x28d80000, 0x28d80000)”的含义,它表示新生代在内存当中的位置:第一个参数是申请到的起始位置,第二个参数是申请到的终点位置,第三个参数表示最多能申请到的位置。上图中的例子表示新生代申请到了15M的控件,而这个15M是等于:(eden space的12288K)+(from space的1536K)+(to space的1536K)

疑问:分配到的新生代有15M,但是可用的只有13824K,为什么会有这个差异呢?等我们在后面的文章中学习到了GC算法之后就明白了。

 

3、指定GC log的位置:

-Xloggc:log/gc.log

解释:指定GC log的位置,以文件输出。帮助开发人员分析问题。


  

-XX:+PrintHeapAtGC

解释:每一次GC前和GC后,都打印堆信息。

例如:


上图中,红框部分正好是一次GC,红框部分的前面是GC之前的日志,红框部分的后面是GC之后的日志。

 

-XX:+TraceClassLoading

解释:监控类的加载。

例如:

[Loaded java.lang.Object from shared objects file]

[Loaded java.io.Serializable from shared objects file]

[Loaded java.lang.Comparable from shared objects file]

[Loaded java.lang.CharSequence from shared objects file]

[Loaded java.lang.String from shared objects file]

[Loaded java.lang.reflect.GenericDeclaration from shared objects file]

[Loaded java.lang.reflect.Type from shared objects file]

 

-XX:+PrintClassHistogram

 

解释:按下Ctrl+Break后,打印类的信息。

例如:


 

二、堆的分配参数:

1、-Xmx –Xms指定最大堆和最小堆

举例、当参数设置为如下时:

-Xmx20m -Xms5m

然后我们在程序中运行如下代码:

System.out.println("Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");     //系统的最大空间
System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M"); //系统的空闲空间
System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M"); //当前可用的总空间

 运行效果:


保持参数不变,在程序中运行如下代码:(分配1M空间给数组)

复制代码
byte[] b = new byte[1 * 1024 * 1024];
System.out.println("分配了1M空间给数组");
System.out.println(
"Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M"); //系统的最大空间
System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M"); //系统的空闲空间
System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
复制代码

运行效果:


注:Java会尽可能将total mem的值维持在最小堆。

保持参数不变,在程序中运行如下代码:(分配10M空间给数组)

复制代码
byte[] b = new byte[10 * 1024 * 1024];
System.out.println("分配了10M空间给数组");
System.out.println(
"Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M"); //系统的最大空间
System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M"); //系统的空闲空间
System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M"); //当前可用的总空间
复制代码

运行效果:


如上图红框所示:此时,total mem 为7M时已经不能满足需求了,于是total mem涨成了16.5M

 

保持参数不变,在程序中运行如下代码:(进行一次GC的回收)

复制代码
System.gc();
System.out.println(
"Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M"); //系统的最大空间
System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M"); //系统的空闲空间
System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M"); //当前可用的总空间 
复制代码

运行效果:


问题1: -Xmx(最大堆空间)和 –Xms(最小堆空间)应该保持一个什么关系,可以让系统的性能尽可能的好呢?

问题2:如果你要做一个Java的桌面产品,需要绑定JRE,但是JRE又很大,你如何做一下JRE的瘦身呢?

 

2、-Xmn、-XX:NewRatio、-XX:SurvivorRatio:

  • -Xmn

    设置新生代大小

  • -XX:NewRatio

    新生代(eden+2*s)和老年代(不包含永久区)的比值

        例如:4,表示新生代:老年代=1:4,即新生代占整个堆的1/5

  • -XX:SurvivorRatio(幸存代)

    设置两个Survivor区和eden的比值

        例如:8,表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10

 

现在运行如下这段代码:

复制代码
public class JavaTest {public static void main(String[] args) {byte[] b = null;for (int i = 0; i < 10; i++)b = new byte[1 * 1024 * 1024];}
}
复制代码

我们通过设置不同的jvm参数,来看一下GC日志的区别。

 

(1)当参数设置为如下时:(设置新生代为1M,很小)

-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails 

运行效果:


总结:

  没有触发GC

    由于新生代的内存比较小,所以全部分配在老年代。

 

(2)当参数设置为如下时:(设置新生代为15M,足够大)

-Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails

运行效果:


上图显示:

没有触发GC

全部分配在eden(蓝框所示)

老年代没有使用(红框所示)

 

(3)当参数设置为如下时:(设置新生代为7M,不大不小)

-Xmx20m -Xms20m –Xmn7m -XX:+PrintGCDetails

运行效果:


总结:

  进行了2次新生代GC

  s0 s1 太小,需要老年代担保

 

(4)当参数设置为如下时:(设置新生代为7M,不大不小;同时,增加幸存代大小)

-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails

运行效果:


总结:

    进行了至少3次新生代GC

    s0 s1 增大

 

(5)当参数设置为如下时:

-Xmx20m -Xms20m -XX:NewRatio=1-XX:SurvivorRatio=2 -XX:+PrintGCDetails 

运行效果:


 

 

(6)当参数设置为如下时: 和上面的(5)相比,适当减小幸存代大小,这样的话,能够减少GC的次数

-Xmx20m -Xms20m -XX:NewRatio=1-XX:SurvivorRatio=3 -XX:+PrintGCDetails


 

 

3、-XX:+HeapDumpOnOutOfMemoryError、-XX:+HeapDumpPath

  • -XX:+HeapDumpOnOutOfMemoryError

    OOM时导出堆到文件

      根据这个文件,我们可以看到系统dump时发生了什么。

  • -XX:+HeapDumpPath

    导出OOM的路径

例如我们设置如下的参数:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

上方意思是说,现在给堆内存最多分配20M的空间。如果发生了OOM异常,那就把dump信息导出到d:/a.dump文件中。

然后,我们执行如下代码:

Vector v = new Vector();
for (int i = 0; i < 25; i++)v.add(new byte[1 * 1024 * 1024]);

上方代码中,需要利用25M的空间,很显然会发生OOM异常。现在我们运行程序,控制台打印如下:


现在我们去D盘看一下dump文件:

8782a0ae-62fb-43a8-a5a6-1c5691e7fa59

上图显示,一般来说,这个文件的大小和最大堆的大小保持一致。

我们可以用VisualVM打开这个dump文件。

注:关于VisualVM的使用,可以参考下面这篇博客:

使用 VisualVM 进行性能分析及调优:http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/

或者使用Java自带的Java VisualVM工具也行:

f9158d50-95d0-4732-942c-e872181fa530

f69bd0d2-a355-4a93-81c1-c3e71bce7509

上图中就是dump出来的文件,文件中可以看到,一共有19个byte已经被分配了。 

 

4、-XX:OnOutOfMemoryError:

  • -XX:OnOutOfMemoryError

    在OOM时,执行一个脚本。

      可以在OOM时,发送邮件,甚至是重启程序。

例如我们设置如下的参数:

-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p //p代表的是当前进程的pid 

上方参数的意思是说,执行printstack.bat脚本,而这个脚本做的事情是:D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt,即当程序OOM时,在D:/a.txt中将会生成线程的dump。

5、堆的分配参数总结:

  • 根据实际事情调整新生代和幸存代的大小
  • 官方推荐新生代占堆的3/8
  • 幸存代占新生代的1/10
  • 在OOM时,记得Dump出堆,确保可以排查现场问题

 

6、永久区分配参数:

  • -XX:PermSize  -XX:MaxPermSize

    设置永久区的初始空间和最大空间。也就是说,jvm启动时,永久区一开始就占用了PermSize大小的空间,如果空间还不够,可以继续扩展,但是不能超过MaxPermSize,否则会OOM。

    他们表示,一个系统可以容纳多少个类型

代码举例:

我们知道,使用CGLIB等库的时候,可能会产生大量的类,这些类,有可能撑爆永久区导致OOM。于是,我们运行下面这段代码:

for(int i=0;i<100000;i++){CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());
}

上面这段代码会在永久区不断地产生新的类。于是,运行效果如下:

fd7bcefb-d6d5-4fe0-8d77-9cddae2733fc

总结:

  如果堆空间没有用完也抛出了OOM,有可能是永久区导致的

    堆空间实际占用非常少,但是永久区溢出 一样抛出OOM。

 

三、栈的分配参数:

1、Xss:

设置栈空间的大小。通常只有几百K

  决定了函数调用的深度

  每个线程都有独立的栈空间

  局部变量、参数 分配在栈上

注:栈空间是每个线程私有的区域。栈里面的主要内容是栈帧,而栈帧存放的是局部变量表,局部变量表的内容是:局部变量、参数。

我们来看下面这段代码:(没有出口的递归调用)

复制代码
public class TestStackDeep {private static int count = 0;
public static void recursion(long a, long b, long c) {long e = 1, f = 2, g = 3, h = 4, i = 5, k = 6, q = 7, x = 8, y = 9, z = 10;count++;recursion(a, b, c);}
public static void main(String args[]) {try {recursion(0L, 0L, 0L);} catch (Throwable e) {System.out.println("deep of calling = " + count);e.printStackTrace();}} }
复制代码

上方这段代码是没有出口的递归调用,肯定会出现OOM的。

如果设置栈大小为128k:

-Xss128K 

运行效果如下:(方法被调用了294次)

5c2b2060-e54a-4e7c-9a30-81567204d55b

如果设置栈大小为256k:(方法被调用748次)

7d6be7d6-b646-42bf-9357-1a3bccbb7a49

意味着函数调用的次数太深,例如递归调用。

 

总结:

我们在本文中介绍了jvm的一些最基本的参数,还有很多参数(如GC参数等)将在后续的系列文章中进行介绍。我们将在接下来的文章中介绍GC算法。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330951.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jvm系列(四):jvm调优-命令篇

转载自 jvm系列(四):jvm调优-命令篇 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题&#xff01;虽然jvm调优成熟的工具已经有很多&#xff1a;jconsole、大名鼎鼎的VisualVM&#xff0c;IBM的Memory Analyzer等等&#xff0c;但是在生产环境出…

Sprng boot(十三):Spring boot 小技巧

初始化数据 使用jpa 在使用Spring boot jpa的情况下设置 spring.jpa.hibernate.ddl-auto 的属性为 create 或 create-drop &#xff0c;Spring boot启动时默认会扫描classpath下面&#xff08;项目一般是resources目录&#xff09;是否有import.sql&#xff0c;如果有机会执行…

滴滴2017在线笔试有感

呵呵 刚才参加完了 滴滴2017的在线笔试。 又一次被虐。。班上很多人都在耍算法&#xff0c;这样算法 那样算法。其实今天看他的 题目 也就是 数据结构的基础知识&#xff0c; 没有多高深的算法。。当然这是一个小生的 匹夫之言&#xff1b; 编程第一题&#xff1a; 求最大子序列…

Mybatis3 XML属性配置

对象工厂&#xff08;ObjectFactory&#xff09; MyBatis 每次创建结果对象的新实例时&#xff0c;它都会使用一个对象工厂&#xff08;ObjectFactory&#xff09;实例来完成。默认的对象工厂需要做的仅仅是实例化目标类。如果想覆盖对象工厂的默认行为&#xff0c;则可以通过…

Eclipse反编译工具Jad及插件JadClipse配置

转自&#xff1a;http://www.blogjava.net/landon/archive/2010/07/16/326294.html Jad是一个Java的一个反编译工具&#xff0c;是用命令行执行&#xff0c;和通常JDK自带的java&#xff0c;javac命令是一样的。不过因为是控制台运行&#xff0c;所以用起来不太方便。不过幸好有…

jvm系列(五):Java GC 分析

转载自 jvm系列(五):Java GC 分析Java GC就是JVM记录仪&#xff0c;书画了JVM各个分区的表演。 什么是 Java GC Java GC&#xff08;Garbage Collection&#xff0c;垃圾收集&#xff0c;垃圾回收&#xff09;机制&#xff0c;是Java与C/C的主要区别之一&#xff0c;作为Java开…

Mybatis3 (2)xml映射文件

SQL 映射文件有很少的几个顶级元素&#xff08;按照它们应该被定义的顺序&#xff09;&#xff1a; cache – 给定命名空间的缓存配置。cache-ref – 其他命名空间缓存配置的引用。resultMap – 是最复杂也是最强大的元素&#xff0c;用来描述如何从数据库结果集中来加载对象。…

面向对象进阶

第一章 类 1.1 如何定义类 类的定义格式如下: 修饰符 class 类名 {// 1.成员变量&#xff08;属性&#xff09;// 2.成员方法 (行为) // 3.构造方法 &#xff08;初始化类的对象数据的&#xff09; }例如: public class Student {// 1.成员变量public String name ;public c…

foreach 循环详解

译自&#xff1a;http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html考虑如下代码&#xff08;方式一&#xff09;&#xff1a;迭代一个 collection 集合对象&#xff0c;然后删除集合元素void cancelAll(Collection<TimerTask> c) {for (Iterator&l…

jvm系列(六):Java服务GC参数调优案例

转载自 jvm系列(六):Java服务GC参数调优案例本文介绍了一次生产环境的JVM GC相关参数的调优过程&#xff0c;通过参数的调整避免了GC卡顿对JAVA服务成功率的影响。 这段时间在整理jvm系列的文章&#xff0c;无意中发现本文&#xff0c;作者思路清晰通过步步分析最终解决问题。我…

Mybatis3(3)动态 SQL

可以利用动态SQL摆脱凭借SQL语句的痛苦。 MyBatis 3 大大精简了元素种类&#xff0c;现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。 ifchoose (when, otherwise)trim (where, set)foreach if 动态 SQL 通常要做的事情是…

jvm系列(七):jvm调优-工具篇

转载自 jvm系列(七):jvm调优-工具篇16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面&#xff0c;其中就包括如何利用工具来监控调优前后的性能变化。工具做为图形化界面来展示更能直观的发现问题&#xff0c;另一方面一些耗费性能的分…

如何不用 List.clear() 方法 就清空 list 中的 所有元素(中兴面试)

import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List;// 涛哥 1609251501 // 如何不用 List.clear() 方法 就清空 list 中的 所有元素. public class MyList {public static void main(String[] args) {List<String>…

mybatis-spring 入门到实例

入门 安装 在pom.xml中导入mybatis-spring.jar包 快速入门 要把spring和mybatis一起使用&#xff0c;需要定义两样东西&#xff1a;SqlsessionFactory 和 至少一个数据库映射器类。 SqlSessionFactoryBean 是用于创建 SqlSessionFactory 的&#xff0c;需要一个Datasource…

在 eclipse 中 设置 jvm 的 运行时目录

然而 在 eclipse中 类所在包的目录是项目所在目录的 孙子目录 而不是 父目录&#xff1b;所以&#xff0c;如果要运行 诸如 chapter18.className这样的类 就需要 将 运行时目录设置为 项目目录/src 目录才行。

jvm系列(九):如何优化Java GC

转载自 jvm系列(九):如何优化Java GC「译」本文翻译自Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三篇《How to Tune Java Garbage Collection》,本文的作者是韩国人&#xff0c;写在JDK 1.8发布之前&#xff0c;虽然有些地方有些许过时&…

关闭json引用的方式

https://www.cnblogs.com/zjrodger/p/4630237.html 【具体方案】 1、如果你用的是FastJson&#xff0c;首先要关闭FastJson的“循环引用检测”特性。 2、如果你不想修改实体之间的关系&#xff0c;则将代码&#xff1a;“JSONField(serializefalse)”添加在下列方法中 public …

Redis学习记录

Redis简介 Redis是一个高性能的key-value非关系型数据库&#xff0c;可以存键&#xff08;key&#xff09;与5中不同类型的值&#xff08;value&#xff09;之间的映射&#xff08;mapping&#xff09;。 支持存储的value类型包括&#xff1a;String&#xff08;字符串&#…

jvm系列(十):教你如何成为Java的OOM Killer

转载自 jvm系列(十):教你如何成为Java的OOM Killer前言 虽然事隔半年&#xff0c;当时排查线上OOM事故的过程记忆犹新&#xff0c;每一个步骤都历历在目&#xff0c;感谢业务组、系统部、压测组、监控与应急部对架构组的强力支持&#xff0c;得以让这个Java内存问题水落石出&am…

java 程序的初始化顺序是怎样的?

【0】README 1&#xff09;本文 转自“ java 程序员面试笔试宝典”&#xff0c; 这个书有点意思&#xff1b; 【1】java程序初始化遵循三个原则&#xff08;rule&#xff09; r1&#xff09;静态变量 优先于 非静态变量&#xff1b; r2&#xff09;父类优先于子类进行初始化&a…