JVM常用参数配置

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Trace跟踪参数 -verbose:gc -XX:+printGC 打印GC的简要信息 -XX:+PrintGCDetails 打印GC详细信息 -XX:+PrintGCTimeStamps 打印CG发生的时间戳 -Xloggc:log/gc.
  • Trace跟踪参数
    • -verbose:gc  -XX:+printGC  打印GC的简要信息
    • -XX:+PrintGCDetails  打印GC详细信息
    • -XX:+PrintGCTimeStamps  打印CG发生的时间戳
    • -Xloggc:log/gc.log  指定GC log的位置,以文件输出
    • XX:+TraceClassLoading  监控类的加载
    • -XX:+PrintClassHistogram  按下Ctrl+Break后,打印类的信息
  • 堆的分配参数
    • -Xmx –Xms  指定最大堆和最小堆
    • -Xmn  设置新生代大小
    • -XX:NewRatio   新生代(eden+2*s)和老年代(不包含永久区)的比值。  例如:4,表示新生代:老年代=1:4,即新生代占整个堆的1/5
    • -XX:SurvivorRatio(幸存代)设置两个Survivor区和eden的比值        例如:8,表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10
    • -XX:+HeapDumpOnOutOfMemoryError   OOM时导出堆到文件  根据这个文件,我们可以看到系统dump时发生了什么。
    • -XX:+HeapDumpPath  导出OOM的路径
    • -XX:OnOutOfMemoryError  在OOM时,执行一个脚本。  可以在OOM时,发送邮件,甚至是重启程序。
    • -XX:PermSize  -XX:MaxPermSize   设置永久区的初始空间和最大空间。也就是说,jvm启动时,永久区一开始就占用了PermSize大小的空间,如果空间还不够,可以继续扩展,但是不能超过MaxPermSize,否则会OOM。
  • 栈的分配参数
    •  -Xss128K  设置栈空间的大小。通常只有几百K  决定了函数调用的深度  每个线程都有独立的栈空间  局部变量、参数 分配在栈上
 

在IDE的后台打印GC日志:

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

bc5b8afb-9d1f-438b-9225-ee7fbbbe2454

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

f2c896da-404c-4415-98ef-5b582dec3528

 

一、Trace跟踪参数:

1、打印GC的简要信息:

-verbose:gc
-XX:+printGC

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

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

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

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

 

2、打印GC的详细信息:

-XX:+PrintGCDetails

解释:打印GC详细信息。

-XX:+PrintGCTimeStamps

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

 

理解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日志:

1fe41f36-cc6b-4a8b-b48e-8cbe2e3a04af

上图中,我们先看一下用红框标注的“[0x27e80000, 0x28d80000, 0x28d80000)”的含义,它表示新生代在内存当中的位置:第一个参数是申请到的起始位置,第二个参数是申请到的终点位置,第三个参数表示最多能申请到的位置。

上图中的例子表示新生代申请到了15M的控件,而这个15M是等于:(eden space的12288K)+(from space的1536K)+(to space的1536K)

 

3、指定GC log的位置:

-Xloggc:log/gc.log

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

-XX:+PrintHeapAtGC

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

例如:

1c6f3837-4b31-4ac2-a639-e79c92f80df5

上图中,红框部分正好是一次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]

 

-XX:+PrintClassHistogram

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

例如:

c8050739-0029-47cd-95bd-fbbd6289a5d1

 

二、堆的分配参数:

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"); //当前可用的总空间

 运行效果:

79c1029d-58fe-47d9-aa2e-1c5ee7e741cd

保持参数不变,在程序中运行如下代码:(分配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");

运行效果:

14d260c9-28bf-4544-a36f-ee14a1d59623

注: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"); //当前可用的总空间

运行效果:

284e8036-8d70-46bc-aac1-99c9b3deb3ef

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

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

byte[] b = new byte[10 * 1024 * 1024];
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"); //当前可用的总空间 

运行效果:

e419c020-0da3-4046-9b7f-f542ee14a780

 

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  

 

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异常。现在我们运行程序,控制台打印如下:

3320aba5-2aa6-42bc-b656-57bbc5d8ec41

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

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

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

我们可以用VisualVM打开这个dump文件。或者使用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。

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

意味着函数调用的次数太深,像这种递归调用就是个典型的例子。


















 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
Arthas 监控 Java
(十一)JVM成神路之性能调优篇:GC调优、Arthas工具详解及各场景下线上最佳配置推荐
“在当前的互联网开发模式下,系统访问量日涨、并发暴增、线上瓶颈等各种性能问题纷涌而至,性能优化成为了现时代开发过程中炙手可热的名词,无论是在开发、面试过程中,性能优化都是一个常谈常新的话题”。
363 3
|
15天前
|
监控 架构师 Java
JVM进阶调优系列(6)一文详解JVM参数与大厂实战调优模板推荐
本文详述了JVM参数的分类及使用方法,包括标准参数、非标准参数和不稳定参数的定义及其应用场景。特别介绍了JVM调优中的关键参数,如堆内存、垃圾回收器和GC日志等配置,并提供了大厂生产环境中常用的调优模板,帮助开发者优化Java应用程序的性能。
|
20天前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
36 3
|
4月前
|
缓存 安全 算法
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
41 0
|
20天前
|
Java Android开发 开发者
【编程进阶知识】精细调控:掌握Eclipse JVM参数配置的艺术
本文详细介绍了如何在Eclipse中配置JVM参数,包括内存的初始和最大值设置。通过具体步骤和截图演示,帮助开发者掌握JVM参数的精细调控,以适应不同的开发和测试需求。
35 1
|
3月前
|
Java
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
|
4月前
|
运维 Java Linux
(九)JVM成神路之性能调优、GC调试、各内存区、Linux参数大全及实用小技巧
本章节主要用于补齐之前GC篇章以及JVM运行时数据区的一些JVM参数,更多的作用也可以看作是JVM的参数列表大全。对于开发者而言,能够控制JVM的部分也就只有启动参数了,同时,对于JVM的性能调优而言,JVM的参数也是基础。
|
3月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
249 0
|
4月前
|
Java
Jinfo 查看 jvm 配置及使用 Jstat 查看堆内存使用与垃圾回收
Jinfo 查看 jvm 配置及使用 Jstat 查看堆内存使用与垃圾回收
115 5
|
3月前
|
运维 监控 Java
【JVM 调优秘籍】实战指南:JVM 调优参数全解析,让 Java 应用程序性能飙升!
【8月更文挑战第24天】本文通过一个大型在线零售平台的例子,深入探讨了Java虚拟机(JVM)性能调优的关键技术。面对应用响应延迟的问题,文章详细介绍了几种常用的JVM参数调整策略,包括堆内存大小、年轻代配置、垃圾回收器的选择及日志记录等。通过具体实践(如设置`-Xms`, `-Xmx`, `-XX:NewRatio`, `-XX:+UseParallelGC`等),成功降低了高峰期的响应时间,提高了系统的整体性能与稳定性。案例展示了合理配置JVM参数的重要性及其对解决实际问题的有效性。
93 0