JVM 中你不得不知的一些参数
有的同学虽然写了一段时间 Java 了,但是对于 JVM 却不太关注。有的同学说,参数都是团队规定好的,部署的时候也不用我动手,关注它有什么用,而且,JVM 这东西,听上去就感觉很神秘很高深的样子,还是算了吧。
没错,部署的时候可能用不到你亲自动手,但是出现问题了怎么办,难道不用你解决问题吗,如果对 JVM 了解不够的话,有些问题可能排查起来就很费力,或者根本无法解决。
本篇以 JDK Hotspot 8 为背景,介绍一下 JVM 的常用参数。建议你在做一些小项目、小 demo 的时候,也把这些参数加上,加深印象。以我的经验来看,有些知识你刚开始接触的时候会感觉很难理解,但是没关系,万事开头难嘛,知识点都是需要消化时间的。第一天不理解,甚至过了一个月也不理解,但是总有那么一刻,你会突然有种茅塞顿开的感觉,感觉一下子通了。最后心里面感谢自己在多少多少天以前能够开始学习并坚持学习这些知识点。
只介绍一些常用参数,除了这些常用参数外,Hotspot 还提供了很多其他的参数,每一个都值得考究。
在使用这些参数之前,你需要对 Java 内存模型有一定的了解,可以读一下 这篇文章 了解一下内存模型。
还是要把内存模型图放在这里,方便理解。
堆参数:
-Xms: 堆的初始值,例如 -Xmx2048,初始堆大小为 2G
-Xmx: 堆的最大值,例如 -Xmx2048M,允许最大堆内存 2G
-Xmn: 新生代大小
-XX:SurvivorRatio:Eden 区所占比例,默认是 8,也就是 80%,例如 -XX:SurvivorRatio=8
最好将 -Xms 和 -Xmx 的值设置成一样的值,这样做是为了防止随着堆空间使用量增加,会动态的调整堆空间大小,有一定的性能损耗,不如开始就设置成相同的值,来规避性能损失。
栈参数
-Xss:栈空间大小,栈是线程独占的,所以是一个线程使用栈空间的大小,例如 -Xss256K,如果不设置此参数,默认值是 1M,一般来讲设置成 256K 就足够了。
Metaspace 参数
-XX:MetaspaceSize:Metaspace 空间初始大小,如果不设置的话,默认是20.79M,这个初始大小是触发首次 Metaspace Full GC 的阈值,例如 -XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize:Metaspace 最大值,默认不限制大小,但是线上环境建议设置,例如
-XX:MaxMetaspaceSize=256M
-XX:MinMetaspaceFreeRatio:最小空闲比,当 Metaspace 发生 GC 后,会计算 Metaspace 的空闲比,如果空闲比(空闲空间/当前 Metaspace 大小)小于此值,就会触发 Metaspace 扩容。默认值是 40 ,也就是 40%,例如 -XX:MinMetaspaceFreeRatio=40
-XX:MaxMetaspaceFreeRatio:最大空闲比,当 Metaspace 发生 GC 后,会计算 Metaspace 的空闲比,如果空闲比(空闲空间/当前 Metaspace 大小)大于此值,就会触发 Metaspace 释放空间。默认值是 70 ,也就是 70%,例如 -XX:MaxMetaspaceFreeRatio=70
建议将 MetaspaceSize 和 MaxMetaspaceSize 设置为同样大小,避免频繁扩容。
GC 日志
简单日志
-verbose:gc 或者 -XX:+PrintGC
日志格式:
[GC (Allocation Failure) 7892K->5646K(19456K), 0.0060442 secs]
[GC (Allocation Failure) , 0.0066315 secs]
[Full GC (Allocation Failure) 19302K->13646K(19456K), 0.0032698 secs]
详细日志
#打印详细日志
-XX:+PrintGCDetails
#打印 GC 的时间点
-XX:+PrintGCDateStamps
日志格式:
2019-11-13T14:06:46.099-0800: [GC (Allocation Failure) 2019-11-13T14:06:46.099-0800: [DefNew (promotion failed) : 9180K->9157K(9216K), 0.0084297 secs]2019-11-13T14:06:46.107-0800: [Tenured: 10145K->10145K(10240K), 0.0035768 secs] 13802K->13646K(19456K), [Metaspace: 3895K->3895K(1056768K)], 0.0120887 secs] [Times: user=0.00 sys=0.00, real=0.02 secs]
2019-11-13T14:06:47.243-0800: [Full GC (Allocation Failure) 2019-11-13T14:06:47.244-0800: [Tenured: 10145K->10145K(10240K), 0.0042686 secs] 19304K->19146K(19456K), [Metaspace: 3895K->3895K(1056768K)], 0.0043232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
以下几个 GC 日志相关的参数打印的内容比较多,生产环境可选择性开启,大多数时候不需要开启。
GC 前后的堆信息
-XX:+PrintHeapAtGC
{Heap before GC invocations=0 (full 0):
def new generation total 9216K, used 7892K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
eden space 8192K, 96% used [0x00000007bec00000, 0x00000007bf3b5200,
xxx....
class space used 445K, capacity 462K, committed 512K, reserved 1048576K
Heap after GC invocations=1 (full 0):
def new generation total 9216K, used 1023K [0x00000007bec00000,
xxx...
Metaspace used 3892K, capacity 4646K, committed 4864K, reserved 1056768K
class space used 445K, capacity 462K, committed 512K, reserved 1048576K
}
GC 导致的 Stop the world 时间
-XX:+PrintGCApplicationStoppedTime
Total time for which application threads were stopped: 0.0070384 seconds, Stopping threads took: 0.0000200 seconds
加载类信息
-verbose:class
[Loaded java.net.URLClassLoader$3$1 from /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar]
GC 前后的类加载情况
-XX:+PrintClassHistogramBeforeFullGC
-XX:+PrintClassHistogramAfterFullGC
num #instances #bytes class name
----------------------------------------------
1: 140 19016264 [B
2: 2853 226256 [C
3: 138 169072 [I
4: 761 86240 java.lang.Class
5: 2850 68400 java.lang.String
6: 660 41024 [Ljava.lang.Object;
日志输出到文件
以上参数配置好之后,默认会输出到控制台或者服务指定的统一日志的位置。但是这里还会有服务的一般性信息日志、错误日志等,都混在一起的话会比较乱,所以,一般都会把 jvm 日志单独存放。
#GC 活动日志,根据配置的参数输出内容
-Xloggc:/Users/fengzheng/jvmlog/gc.log
#致命错误日志,只有在 jvm 发生崩溃的时候会输出
-XX:ErrorFile=/Users/fengzheng/jvmlog/hs_err_pid%p.log
堆溢出现场保留
有些错误虽然不会导致 jvm 崩溃,但是对于服务而言也是非常严重的,比如stackOverflow、OutOfMemoryError,发生错误后,留存现场信息对分析错误原因是至关重要的。jvm 提供了保留堆溢出现场的方法,对于 JDK 8 而言,可能是 heap 溢出,也可能是 Metasapce 溢出。
-XX:HeapDumpPath=/Users/fengzheng/jvmlog
-XX:+HeapDumpOnOutOfMemoryError
最后出现异常后,保存的文件格式为 java_pidxxx.hprof,pid 后面是发生溢出的进程 id,之后可以用 VisualVM、JProfiler 等工具打开分析。
设置垃圾回收器类型
随着 JDK 版本的升级,可使用的垃圾收集器类型也越来越多了。JDK 8 可使用的垃圾收集器有 7 种,当然有点只适用于年轻代,有点只使用于老年代,JDK 8 中最新的垃圾收集器是 G1,可以用于年轻代和老年代。到了 JDK 11,还出了 ZGC。
下图是 JDK 8 中可使用的垃圾收集器以及它们配合使用的关系。
Serial、ParNew、Parallel Scavenge 只适用于年轻代,CMS、Serial Old、Parallel Old 只适用于老年代,而 G1 通用于年轻代和老年代。连线表示它们之间可配合使用的关系,其中 CMS 和 Serial Old 连线的意思是说 Serial Old 会作为 CMS 的后预案,当 CMS 发生 Concurrent Mode Failure 时启用。
在 JDK 8 中,如果不指定垃圾收集器,默认使用参数 -XX:+UseParallelGC
,新生代使用 Parallel Scavenge,老年代使用 Serial Old。
-XX:+UseSerialGC:使用 Serial + Serial Old ,运行于 client 模式下的默认设置
-XX:+UseConcMarkSweepGC:使用 ParNew+CMS+Serial Old,CMS 垃圾收集器
-XX:+UseParallelGC:Parallel Scavenge + Serial Old,JDK 8 server 模式下的默认设置
-XX:+UseParallelOldGC:Parallel Scavenge + Parallel Old
-XX:+UseG1GC:使用 G1 垃圾收集器
开启远程 JMX 监控
除了日志外,当我们需要实时查看 JVM 运行情况的时候怎么办,当然可以到 JVM 所在服务器用 jstack、jmap、jinfo 等工具进行查看,但是又不够直观,这时候就需要开启 JMX 远程功能,使用 jConsole、VisualVM 等工具进行监控。或者自己开发监控平台,比如我之前就做了一个 web 版的简易 VisualVm。无意中就做了个 web 版 JVM 监控端
开启参数如下:
-Dcom.sun.management.jmxremote
#指定 jvm 所在服务器 ip 或域名
-Djava.rmi.server.hostname=192.168.1.1
#指定端口
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
相关阅读:
Java-agent, 调试工具、热部署、JVM 监控工具都用到了它
不要吝惜你的「推荐」呦
欢迎关注,不定期更新本系列和其他文章
古时的风筝
,进入公众号可以加入交流群
JVM 中你不得不知的一些参数的更多相关文章
- 改变JVM中的参数以提高Eclipse的运行速度
首先建立评估体系,将workspace里所有的项目close掉,关闭eclipse.优化的用例就是启动eclipse,open一个项目,eclipse会自动build这个项目,保证没有感觉到明显的卡, ...
- JVM中的GC算法,JVM参数,垃圾收集器分类
一.在JVM中什么是垃圾?如何判断一个对象是否可被回收?哪些对象可以作为GC Roots的根 垃圾就是在内存中已经不再被使用到的空间就是垃圾. 1.引用计数法: 内部使用一个计数器,当有对象被引用+1 ...
- JVM中可生成的最大Thread数量
最近想测试下Openfire下的最大并发数,需要开大量线程来模拟客户端.对于一个JVM实例到底能开多少个线程一直心存疑惑,所以打算实际测试下,简单google了把,找到影响线程数量的因素有下面几个: ...
- 【转】JVM运行原理及JVM中的Stack和Heap的实现过程
来自: http://blog.csdn.net//u011067360/article/details/46047521 Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’( ...
- jvm中的年轻代 老年代 持久代 gc
虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent Generation).其中持久代主要存放的是Java类的类信 ...
- 浅析JVM中的GC日志
目录 一.GC日志的格式分析 二.运行时开启GC日志 一.GC日志的格式分析 在讲述GC日志之前,我们先来运行下面这段代码 package com.example; public class Test ...
- 《深入Java虚拟机学习笔记》- 第7章 类型的生命周期/对象在JVM中的生命周期
一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令 ...
- JVM中的Stack和Heap
Stack: 是内存指令区.Java基本数据类型,Java指令代码,常量都保存在stack中,方法是指令也保存在stack中. 由于stack是内存是顺序分配,而且定长,不存在内存回收问题.存取速度快 ...
- Java虚拟机:JVM中的Stack和Heap
简单的了解一下JVM中的栈和堆 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和 ...
随机推荐
- Hive 官方手册翻译 -- Hive DML(数据操纵语言)
由 Confluence Administrator创建, 最终由 Lars Francke修改于 八月 15, 2018 原文链接 https://cwiki.apache.org/confluen ...
- Python基础库之jieba库的使用(第三方中文词汇函数库)
各位学python的朋友,是否也曾遇到过这样的问题,举个例子如下: “I am proud of my motherland” 如果我们需要提取中间的单词要走如何做? 自然是调用string中的spl ...
- 数据结构(java)
数据结构1.什么是数据结构?数据结构有哪些? 数据结构是指数据在内存中存放的机制. 不同的数据结构在数据的查询,增删该的情况下性能是不一样的. 数据结构是可以模拟业务场景. 常见的数据结构有:栈,队列 ...
- Python中的可变对象与不可变对象、浅拷贝与深拷贝
Python中的对象分为可变与不可变,有必要了解一下,这会影响到python对象的赋值与拷贝.而拷贝也有深浅之别. 不可变对象 简单说就是某个对象存放在内存中,这块内存中的值是不能改变的,变量指向这块 ...
- Python_MySQL数据库的写入与读取
[需求]1. 在数据库中创建表,且能按时间自动创建新表 2. 数据写入数据库 3. 从数据库读取数据 1. 创建表,并自动更新 def Creat_Table(InitMySQL,tabel_name ...
- [JoyOI1519] 博彩游戏
题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目背景 Bob最近迷上了一个博彩游戏…… 题目描述 这个游戏的规则是这样的:每花一块钱可以 ...
- Luogu P2297 刷图 DP
题目背景 loidc,LOI中的传说级哲♂学家,曾经创造一天内入坑maxlongint个弃坑0x7fffffff个的神奇纪录.目前,loidc最喜欢的游戏就是地下城与勇♂士. 题目描述 Loidc是一 ...
- (21)ASP.NET Core EF创建模型(关系)
1.关系 关系定义两个实体之间的关系.在关系型数据库中,这由外键约束表示. 2.术语定义 有许多术语用于描述关系:●相关实体:这是包含外键属性的实体.有时称为关系的"子级".●主体 ...
- 《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化
概述 Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运 ...
- ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
1. 前言 在前面的篇章中,博主给大家讲解了ESP8266的软硬件配置以及基本功能使用,目的就是想让大家有个初步认识.并且,博主一直重点强调 ESP8266 WiFi模块有三种工作模式: St ...