jvm内存参数配置_“步步精心”-常用JVM配置参数
本文主要内容:
- 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文件:
上图显示,一般来说,这个文件的大小和最大堆的大小保持一致。
我们可以用VisualVM打开这个dump文件。
注:关于VisualVM的使用,可以参考下面这篇博客:
使用 VisualVM 进行性能分析及调优:http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/
或者使用Java自带的Java VisualVM工具也行:
上图中就是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());}
上面这段代码会在永久区不断地产生新的类。于是,运行效果如下:
总结:
如果堆空间没有用完也抛出了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次)
如果设置栈大小为256k:(方法被调用748次)
意味着函数调用的次数太深,像这种递归调用就是个典型的例子。
如果你们觉得文章写的不错,欢迎转发关注!
jvm内存参数配置_“步步精心”-常用JVM配置参数相关推荐
- 19.jvm内存结构部分——堆_内存诊断_jmap
接下来我们给大家介绍一下堆内存的一个诊断. 这里主要先介绍一些堆内存诊断相关的一些工具. 我们接下来会掌握这样几个工具啊, 第一个叫 jps 的工具,它是查看当前系统中有哪些java 进程,并且把它们 ...
- JVM内存调优原则及几种JVM内存调优方法
JVM内存调优原则及几种JVM内存调优方法 1.堆大小设置. 2.回收器选择. 1.在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因 ...
- JVM参数太多?一网打尽常用JVM参数!
JVM提供的参数非常多,并且各种类型的参数能够提供不同的功能 理解JVM运行原理和熟悉常用JVM参数能够帮助我们更好的进行调优 本篇文章将介绍JVM参数的分类,以及GC日志.运行时内存区.OOM.垃圾 ...
- eclipse java启动参数设置_[Java教程]eclipse.ini配置eclipse的启动参数
[Java教程]eclipse.ini配置eclipse的启动参数 0 2013-09-28 01:00:11 Eclipse的启动由$ECLIPSE_HOME/eclipse.ini控制,如果$EC ...
- 伺服电机常用参数设置_伺服电机驱动器的几个参数设置
伺服电机驱动器的正确使用除按用户手册正确设置参数外,还应结合使用现场和负载情况,灵活操作.同样,维修伺服电机系统除采用同型号的部件进行替代外,也可以对原设备的功能.信号分析后,使用不同型号部件进行替代 ...
- hdfs 备份数配置_大数据||HDFS HA配置详解
根据HA架构图,规划HA的分布式集群服务器 HA集群规划 配置参考图 根据官方文档配置HA 部分说明 Architecture 在典型的ha集群中,两台独立的机器被配置为namenode.在任何时间点 ...
- python要什么电脑配置_学Python需要什么配置的电脑?
首先,如果你开始从学习Python语言本身的角度来看,你不需要配置一台电脑,太高,普通办公电脑能完全满足要求,或目前大部分笔记本电脑销售能够满足基本的学习需求.然而,学习Python通常需要一个相对明 ...
- python函数定义中参数列表里的参数是_详解Python函数中参数带星号是什么意思
函数的参数使用除了常规的位置参数和关键字参数外,还支持可变个数的函数参数,这种支持可变个数的参数方法称为参数收集,对应的参数称为收集参数. 一.参数收集的定义 Python的函数支持可变不定数量的参数 ...
- 华为交换机导入配置_将一个华为交换机的配置导入另一个已有配置的交换机中...
1.金锄头文库是"C2C"交易模式,即卖家上传的文档直接由买家下载,本站只是中间服务平台,本站所有文档下载所得的收益全部归上传人(卖家)所有,作为网络服务商,若您的权利被侵害请及时 ...
最新文章
- 提高C++性能的编程技术笔记:多线程内存池+测试代码
- 认知AI的兴起:2025年AI将会发生质的飞跃
- 中国蚁剑的下载、安装与使用
- MULE ESB中custom,flows,connectors等的使用方法
- ERP实施实记(六)之生管课
- 数据结构 - 二叉树 - 面试中常见的二叉树算法题
- 一维OTSU法、最小交叉熵法、二维OTSU法及C++源码
- 谭浩强c语言规范化的指数形式,C语言程序设计谭浩强第四期末复习重点.docx
- Struts2中ActionContext介绍
- 课后作业(因博客源问题,发的邮箱作业,重新提交博客园)
- 【软件项目管理】软件项目的主要成本是人的劳动的消耗
- oracle内存架构(一)
- garmone build on sb2
- 暴雨公式 matlab,对雨水暴雨强度公式中降雨历时分解.pdf
- 面包板入门电子制作 学习笔记5
- python 全角字符和半角字符切换
- 【协议森林】基于DPDK的原生态协议栈DPDK-ANS
- 微信突破版本限制永久设置透明/半透明头像
- html打印26个字母,用js完成:输出26个英文字母任意3个字母的全部组合
- 25 scala 进阶
热门文章
- 《终身成长》读书笔记(part6)--真正的自信来源于你的思维模式:你已经做好了成长的准备
- 程序员面试金典适合java么,【程序员面试金典】面试题 01.03. URL化(示例代码)
- Kyma Application Connectivity 特性介绍
- SAP UI5 应用开发教程之三十五 - 如何把本地开发的 SAP UI5 应用部署到 ABAP 服务器上试读版
- 发现 postman 自动生成接口调用代码的一个问题
- SAP Spartacus 服务器端渲染的三种可能情形
- de.hybris.platform.servicelayer.dto.converter.ConversionException
- TypeScript 的变量定义
- SAP Spartacus BrowserPlatformLocation的初始化逻辑
- Angular getOrCreateInjectable的实现原理调试