JVM优化之优化常用参数和工具
JVM优化之优化常用参数和工具
内容提要
- jvm运行参数和参数设置
- jvm 内存模型
- 定位分析死锁和内存溢出
- 其他工具使用
为什么要优化JVM
1.生产环境需要承载更多的并发要求,对底层的优化能显著提升性能,节约成本
2.测试和生产环境的不同可能导致我们无法实时了解具体性能问题,我们需要借助对JVM了解分析问题所在。
jvm运行参数和参数设置
1.标准参数
由java -help检索出来的所有参数成为标准参数,未来发行版本中不会轻易修改,即使修改也会有官方通知
>java -help-java [-options] class [args...] (执行类)或 java [-options] -jar jarfile [args...] #(执行 jar 文件)其中选项包括:-D<名称>=<值> #设置系统属性-version #输出产品版本并退出-showversion # 输出产品版本并继续-? -help 输出此帮助消息-X #输出非标准选项的帮助-d32 #使用 32 位数据模型 (如果可用)-d64 #使用 64 位数据模型 (如果可用)-server #选择 "server" VM 默认 VM 是 server,因为您是在服务器类计算机上运行。-cp <目录和 zip/jar 文件的类搜索路径>-classpath <目录和 zip/jar 文件的类搜索路径> #用 : 分隔的目录, JAR 档案和 ZIP 档案列表, 用于搜索类文件。###########################以上为非常重要的参数 希望开发者一定要记住###########################-verbose:[class|gc|jni] #启用详细输出-version:<值> #警告: 此功能已过时, 将在未来发行版中删除。需要指定的版本才能运行-jre-restrict-search | -no-jre-restrict-search #警告: 此功能已过时, 将在未来发行版中删除。在版本搜索中包括/排除用户专用 JRE-ea[:<packagename>...|:<classname>]-enableassertions[:<packagename>...|:<classname>]#按指定的粒度启用断言-da[:<packagename>...|:<classname>]-disableassertions[:<packagename>...|:<classname>] #禁用具有指定粒度的断言-esa | -enablesystemassertions # 启用系统断言-dsa | -disablesystemassertions # 禁用系统断言-agentlib:<libname>[=<选项>] #加载本机代理库 <libname>, 例如 -agentlib:hprof另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help-agentpath:<pathname>[=<选项>] #按完整路径名加载本机代理库-javaagent:<jarpath>[=<选项>] #加载 Java 编程语言代理, 请参阅 java.lang.instrument-splash:<imagepath> # 使用指定的图像显示启动屏幕
使用Java代码测试系统属性
Properties properties = System.getProperties();for (Map.Entry<Object, Object> objectObjectEntry : properties.entrySet()) {System.out.printf("system prop : %s = %s\n",objectObjectEntry.getKey(),objectObjectEntry.getValue());}
// java -Dmyname=huyiyu [类名] 之后在打印所有系统参数中找到myname=huyiyu
server和client参数
server: 显式指定-server时设置,或者64位系统时设置,使用 parNew GC 1 启动慢运行快
client:显式指定-client时设置,或者64位系统时设置,使用default GC2启动快运行慢
系统信息如下:
windowsX86 | 其他X86 | 其他X86 Mem:>2GB >2CPU | X64 |
---|---|---|---|
client | client | server | server |
2.非标准参数
-Xmixed # 混合模式执行 (默认)
-Xint #仅解释模式执行
-Xbatch #禁用后台编译
-Xms<size> #设置初始 Java 堆大小
-Xmx<size> #设置最大 Java 堆大小
-Xss<size> #设置 Java 线程堆栈大小
-XshowSettings #显示所有设置并继续
########################以上参数非常重要需要记住###############################
-XshowSettings:all#显示所有设置并继续
-XshowSettings:vm 显示所有与 vm 相关的设置并继续
-XshowSettings:properties #显示所有属性设置并继续
-XshowSettings:locale#显示所有与区域设置相关的设置并继续
-Xbootclasspath: <用 : 分隔的目录和 zip/jar 文件> #设置搜索路径以引导类和资源
-Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>#附加在引导类路径末尾
-Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>#置于引导类路径之前
-Xdiag #显示附加诊断消息
-Xnoclassgc #禁用类垃圾收集
-Xincgc #启用增量垃圾收集
-Xloggc:<file> #将 GC 状态记录在文件中 (带时间戳)
-Xprof #输出 cpu 配置文件数据
-Xfuture #启用最严格的检查, 预期将来的默认值
-Xrs #减少 Java/VM 对操作系统信号的使用 (请参阅文档)
-Xcheck:jni #对 JNI 函数执行其他检查
-Xshare:off #不尝试使用共享类数据
-Xshare:auto #在可能的情况下使用共享类数据 (默认)
-Xshare:on #要求使用共享类数据, 否则将失败。
#-X 选项是非标准选项, 如有更改, 恕不另行通知。
设置编译模式
类型 | 说明 | 示例 | 用法 | 备注 |
---|---|---|---|---|
int | 解释模式 | -Xint | -Xint | 强制运行字节码,效率低 |
comp | 编译模式 | -Xcomp | -Xcomp | 编译成native代码带来大程度的优化 |
mix | 混合模式 | -Xmix | -Xmix | 解释和编译混合进行,由jvm决定使用任意推荐使用 |
设置初始堆内存
类型 | 说明 | 示例 | 用法 | 备注 |
---|---|---|---|---|
Xms | 最小堆内存 | -Xms<数字><单位> | -Xmx1024m | 设置最小堆内存为1024MB |
Xmx | 最大堆内存 | -Xmx<数字><单位> | -Xms1024m | 设置最大堆内存为1024MB |
Xss | 初始堆内存 | -Xmx<数字><单位> | -Xss1024m | 设置初始堆内存为1024MB |
XX参数
XX参数也是非标准参数,用于jvm调优和debug操作,设置JVM有两种模式分别如下
类型 | 用法 | 示例 | 备注 |
---|---|---|---|
boolean | -XX:+/-<name> | XX:+DisableExplicitGC | +:启用 -:禁用 |
非boolean | :-XX:<name>=<value> | :-XX:NewRatio=1 |
# XX参数实战
-XX:+PrintFlagsFinal -version# =表示默认参数 :=表示重置生效参数bool UseXMMForArrayCopy = true {product} {default}bool UseXMMForObjInit = false {ARCH product} {default}bool UseXmmI2D = false {ARCH product} {default}bool UseXmmI2F = false {ARCH product} {default}bool UseXmmLoadAndClearUpper = true {ARCH product} {default}bool UseXmmRegToRegMoveAll = true {ARCH product} {default}bool VMThreadHintNoPreempt = false {product} {default}intx VMThreadPriority = -1 {product} {default}intx VMThreadStackSize = 0 {pd product} {default}intx ValueMapInitialSize = 11 {C1 product} {default}intx ValueMapMaxLoopSize = 8 {C1 product} {default}intx ValueSearchLimit = 1000 {C2 product} {default}bool VerifyMergedCPBytecodes = true {product} {default}bool VerifySharedSpaces = false {product} {default}...
# 使用jinfo可查看运行的应用的jvm参数 :jinfo pid
jvm 内存模型
JDK1.7 jvm内存模型
jdk7 jvm 堆模型
- Young 年轻区
Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中,Survivor区间中,某一时刻只有
其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Eden区间变满的时候, GC就会将存活的对
象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移
动到Tenured区间。
- Tenured 年老区
Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以
后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转
移到这一区间。
- Perm 永久区
Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在
涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,
造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造
成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。
- Virtual区
最大内存和初始内存的差值,就是Virtual区。
JDK1.8内存模型
JDK1.8的堆内存模型
由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代 + 年老代。
年轻代:Eden + 2*Survivor
年老代:OldGen
在jdk1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换。
需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永
久代最大的区别所在。
JDK1.8废弃永久区的原因
This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need
to configure the permanent generation (since JRockit does not have a permanent
generation) and are accustomed to not configuring the permanent generation.
移除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。
现实使用中,由于永久代内存经常不够用或发生内存泄露,爆出异常java.lang.OutOfMemoryError: PermGen。
基于此,将永久区废弃,而改用元空间,改为了使用本地内存空间。
定位分析死锁和内存溢出
定位死锁
//以下是一段死锁代码
package com.yiyu;public class DeadLock {private static final String LOCK_A = "LOCK_A";private static final String LOCK_B = "LOCK_B";public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> DeadLock.getLock("thread_1", LOCK_A, LOCK_B));Thread thread2 = new Thread(() -> DeadLock.getLock("thread_2", LOCK_B, LOCK_A));thread1.start();thread2.start();}public static void getLock(String user, String lock1, String lock2) {try {synchronized (lock1) {System.out.println(user + "获得了" + lock1 + "的锁");synchronized (lock2) {System.out.println(user + "获得了" + lock2 + "的锁");}}} catch (Exception e) {e.printStackTrace();}}
}
# 使用jps查看进程ID
[root@izwz92w1juq9pnt03ae87yz ~]# jps
10400 Bootstrap
12812 Jps
12733 DeadLock
[root@izwz92w1juq9pnt03ae87yz ~]# jstack 12733
...
Found one Java-level deadlock:
=============================
"Thread-0":waiting to lock monitor 0x00007fa788008900 (object 0x00000000e34c2258, a java.lang.String),which is held by "Thread-1"
"Thread-1":waiting to lock monitor 0x00007fa788006900 (object 0x00000000e34c2228, a java.lang.String),which is held by "Thread-0"Java stack information for the threads listed above:
===================================================
"Thread-0":at DeadLock.getLock(DeadLock.java:17)- waiting to lock <0x00000000e34c2258> (a java.lang.String)- locked <0x00000000e34c2228> (a java.lang.String)at DeadLock.lambda$main$0(DeadLock.java:6)at DeadLock$$Lambda$1/0x0000000100060840.run(Unknown Source)at java.lang.Thread.run(java.base@11.0.1/Thread.java:834)
"Thread-1":at DeadLock.getLock(DeadLock.java:17)- waiting to lock <0x00000000e34c2228> (a java.lang.String)- locked <0x00000000e34c2258> (a java.lang.String)at DeadLock.lambda$main$1(DeadLock.java:7)at DeadLock$$Lambda$2/0x0000000100062840.run(Unknown Source)at java.lang.Thread.run(java.base@11.0.1/Thread.java:834)
Found 1 deadlock."Thread-0" #10 prio=5 os_prio=0 cpu=22.94ms elapsed=369.77s tid=0x00007fa7a8156000 nid=0x31c9 waiting for monitor entry [0x00007fa79081b000]java.lang.Thread.State: BLOCKED (on object monitor)at DeadLock.getLock(DeadLock.java:17) #死锁发生的代码的行- waiting to lock <0x00000000e34c2258> (a java.lang.String)- locked <0x00000000e34c2228> (a java.lang.String)at DeadLock.lambda$main$0(DeadLock.java:6)at DeadLock$$Lambda$1/0x0000000100060840.run(Unknown Source)at java.lang.Thread.run(java.base@11.0.1/Thread.java:834)"Thread-1" #11 prio=5 os_prio=0 cpu=23.86ms elapsed=369.77s tid=0x00007fa7a8157800 nid=0x31ca waiting for monitor entry [0x00007fa79071a000]java.lang.Thread.State: BLOCKED (on object monitor)at DeadLock.getLock(DeadLock.java:17)#死锁发生的代码的行- waiting to lock <0x00000000e34c2228> (a java.lang.String)- locked <0x00000000e34c2258> (a java.lang.String)at DeadLock.lambda$main$1(DeadLock.java:7)at DeadLock$$Lambda$2/0x0000000100062840.run(Unknown Source)
定位内存溢出
package com.yiyu;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;
public class OutOffMemoryErrorTest {public static void main(String[] args) {Stream.iterate(UUID.randomUUID().toString(), a -> a + a).limit(1000).reduce(String::concat).ifPresent(System.out::println);}
}
java -Xmx6m -XX:+HeapDumpOnOutOfMemoryError OutOffMemoryErrorTest 程序运行后会出现内存溢出
具体如下:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid2176.hprof …
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
Heap dump file created [6383576 bytes in 0.029 secs]
at java.base/java.lang.String.concat(String.java:1947)
at com.yiyu.OutOffMemoryErrorTest$$Lambda$18/0x00000001000a8840.apply(Unknown Source)
at java.base/java.util.stream.ReduceOps$2ReducingSink.accept(ReduceOps.java:123)
at java.base/java.util.stream.SliceOps$1$1.accept(SliceOps.java:199)
at java.base/java.util.stream.Stream1.tryAdvance(Stream.java:1231)atjava.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)atjava.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)atjava.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)atjava.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)atjava.base/java.util.stream.ReduceOps1.tryAdvance(Stream.java:1231) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps1.tryAdvance(Stream.java:1231)atjava.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)atjava.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)atjava.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)atjava.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)atjava.base/java.util.stream.ReduceOpsReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:558)
at com.yiyu.OutOffMemoryErrorTest.main(OutOffMemoryErrorTest.java:14)
从项目中找到对应的文件,使用工具分析
jvm其他工具使用
请参考博客jvm分析工具概述,对每个命令的每个操作分析的非常全面,跳转方便以后阅读。
JMX配置
原理是启动Java程序时添加系统参数已达到暴露端口提供接入虚拟机的协议,网上的配置非常详细但是有些不足,使用JMX时会开放三个端口,如果仅仅开启com.sun.management.jmxremote.port会发现 Jconsole活visualVM仍然访问不了,此时 使用netstat -nltp 查询打开另外两个端口或多一行配置即可,具体原因是因为JMX支持本地连接建立的端口。如需知道更详细信息请参考博客:JMX实践-JMX连接端口
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
javax.management.remote.rmi.RMIConnectorServer=9999
并行垃圾收集器 部分stw ↩︎
串行垃圾收集器单线程 全部stw ↩︎
JVM优化之优化常用参数和工具相关推荐
- JVM常用参数与工具
原文出处:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html 目录 参数设置 收集器搭配 启动内存分配 监控工具和方法 调优方法 调优实例 ...
- Java虚拟机学习总结(4)—— JVM 性能调优常用参数详解
前言 在JVM性能调优时有三个组件: 堆大小调整(内存最够大的话,尽量搞大点) 垃圾收集器调整 JIT 编译器(比较深,需要掌握源码才能更好的优化更加底层) 大多数调优选项都与调整堆大小和为您的情况选 ...
- jvm堆空间的常用参数设置
- mysql参数优化步骤_MySQL架构优化实战系列4:SQL优化步骤与常用管理命令2(转)
MySQL架构优化实战系列4:SQL优化步骤与常用管理命令 原文:http://dbaplus.cn/news-11-649-1.html 一.SQL语句优化步骤 1.查看MySQL状态及配置 sho ...
- 高级SQL优化(三) 常用优化工具 ——《12年资深DBA教你Oracle开发与优化——性能优化部分》...
目录: Oracle数据完整性和锁机制 索引及优化之表分析 表分析.约束及表间关系 Oracle体系结构1 Oracle体系结构2 海量数据库及分区1 海量数据库及分区2 海量数据库及分区 ...
- MySQL系列之优化——1.优化哲学、2. 优化工具的使用、3. 优化思路分解、4. MySQL参数优化测试、5.1 参数优化、6. 参数优化结果、7. 锁的监控及处理、8. 主从优化
文章目录 1.优化哲学 1.1 为什么优化? 1.2 优化风险 1.3 谁参与优化 1.4 优化方向 1.5 优化的范围及思路 优化效果和成本的评估: 2. 优化工具的使用 2.1 系统层面的 2.1 ...
- 深入理解JVM(4)——如何优化Java GC「译」
本文翻译自Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三篇<How to Tune Java Garbage C ...
- JVM学习笔记之-堆,年轻代与老年代,对象分配过程,Minor GC、Major GC、Full GC,堆内存大小与OOM,堆空间分代,内存分配策略,对象分配内存,小结堆空间,逃逸分析,常用调优工具
堆的核心概述 概述 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域.Java堆区在JVM 启动的时候即被创建,其空间大小也就确定了.是JVM管理的最大一块内存空间. 堆内存的大小是可 ...
- 一文了解程序员必须要知道的JVM和性能优化知识点
目录 JVM和性能优化 1.Java内存区域 虚拟机的历史 未来的Java技术一览 运行时数据区域 站在线程角度来看堆和栈 深入辨析堆和栈 方法的出入栈 虚拟机中的对象 堆参数设置和内存溢出实战 2. ...
最新文章
- 多学一点(八)——LNMP环境搭建
- 链路负载均衡的链路和NAT地址保持
- 深度学习RNN实现股票预测实战(附数据、代码)
- 重学TCP协议(4) 三次握手
- nuxt 服务器构建因太耗CPU进程被杀解决办法
- tensorflow windows
- java程序嵌入地图_java – 使用JPA存储地图
- 揭密 GaussDB T 主备物理复制搭建过程(全)
- [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBuild+GitHub)
- python使用工具简介介绍
- 最大似然估计、MAP、贝叶斯估计
- java多线程总结一:线程的两种创建方式及比较
- 如何在虚拟机里用win95\98上网
- oracle导出dmp文件报错904,EXP-00008: 遇到 ORACLE 错误 904 ORA-01003
- Informatica使用工作流程及案例1
- 内存cpu占用不高但mysql很卡_为什么cpu占用率不高,内存也不高,电脑会卡
- 无奈.是爱是狠.金山毒霸2007.从此改邪归正
- 02好好学习读书笔记-- 黄金思考圈
- 【数学分析】从多元函数的定义一直到多元函数的泰勒展开
- hapi入门简介(入门实践)----净土小沙弥学hapi.js_第二篇
热门文章
- dnn降噪_万魔降噪双旗舰耳机分享:这两款无线耳机能否取代AirPods Pro?
- C语言 题目 1727: 首字母大写
- java web console,centos 8 如何开启 web console 界面?
- 字节跳动官方回应锤子科技员工改签,锤子二号员工入职OPPO...
- linux中的如何进行磁盘分区
- 2021年塔式起重机司机考试报名及塔式起重机司机模拟考试题
- 修改mySql最大连接数
- HarmonyOS/OpenHarmony按键设备键值
- cocos creator 2.4.3cc.assetManager.loadRemote 加载不了微信头像
- Es6新特性:set