JVM优化之优化常用参数和工具

JVM优化之优化常用参数和工具JVM优化之优化常用参数和工具内容提要jvm运行参数和参数设置jvm内存模型jmap命令的使用以及通过MAT工具分析定位分析内存溢出的方法jstack的使用visualJVM工具使用为什么要优化JVM1.生产环境需要承载更多的并发要求,对底层的优化能显著提升性能,节约成本2.测试和生产环境的不同可能导致我们无法实时了解具体性能问题,我们需要借助对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内存模型

jvm内存模型

jdk7 jvm 堆模型

Java堆模型

  • 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内存模型

JDK8内存模型

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.Stream 1. t r y A d v a n c e ( S t r e a m . j a v a : 1231 ) a t j a v a . b a s e / j a v a . u t i l . s t r e a m . R e f e r e n c e P i p e l i n e . f o r E a c h W i t h C a n c e l ( R e f e r e n c e P i p e l i n e . j a v a : 127 ) a t j a v a . b a s e / j a v a . u t i l . s t r e a m . A b s t r a c t P i p e l i n e . c o p y I n t o W i t h C a n c e l ( A b s t r a c t P i p e l i n e . j a v a : 502 ) a t j a v a . b a s e / j a v a . u t i l . s t r e a m . A b s t r a c t P i p e l i n e . c o p y I n t o ( A b s t r a c t P i p e l i n e . j a v a : 488 ) a t j a v a . b a s e / j a v a . u t i l . s t r e a m . A b s t r a c t P i p e l i n e . w r a p A n d C o p y I n t o ( A b s t r a c t P i p e l i n e . j a v a : 474 ) a t j a v a . b a s e / j a v a . u t i l . s t r e a m . R e d u c e O p s 1.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.ReduceOps 1.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

  1. 并行垃圾收集器 部分stw ↩︎

  2. 串行垃圾收集器单线程 全部stw ↩︎

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/137477.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • AD域介绍

    AD域介绍域的背景介绍为什么要使用域?假设你是公司的系统管理员,你们公司有一千台电脑。如果你要为每台电脑设置登录帐户,设置权限(比如是否允许登录帐户安装软件),那你要分别坐在这一千台电脑前工作。如果你要做一些改变,你也要分别在这一千台电脑上修改。相信没有哪个管理员想要用这种不吃不喝不睡觉的方式来工作,所以就应运而生了域的概念。域(Domain):概念域模型就是针对大型网络的管理需求而设计的,域就是共享用户账号,计算机账号和安全策略的计算机集合。域的管理优点因为所有的用户信息都被集中存储,所以,域提供了集

  • WSUS Troubleshooting guide「建议收藏」

    WSUS Troubleshooting guide「建议收藏」TroubleshootingguideforissueswhereWSUSclientsarenotreportingin来自于WSUSTEAMBLOGThisguideiswrittentoassistspecificallyintroubleshootingWSUSwhenclientsarenotrepor…

  • Django跨域(前端跨域)

    前情回顾在说今天的问题之前先来回顾一下有关Ajax的相关内容Ajax的优缺点jQuery实现的ajaxajax参数请求参数响应参数小练习:计算两个数的和方式一:这里没有指定conten

  • JAVA异或运算符_java位运算符详解

    JAVA异或运算符_java位运算符详解目录目录性质应用举例其他用途示例异或是一种基于二进制的位运算,用符号XOR或者^表示,起运算法则是对运算符两侧数的每一个二进制位同值则取0,异值则取1.简单理解就是不进位加法,如1+1=0,0+0=0,1+0=1.性质1、交换律2、结合律(即(a^b)^c==a^(b^c))3、对于任何数x,都有x^x=0,x^0=x4、自反性AXORBXORB=

  • linux 系统进行make menuconfig的时候出错

    linux 系统进行make menuconfig的时候出错错误信息:(ps:当前系统:Linuxlabpc4.13.0-36-generic#40~16.04.1-UbuntuSMPFriFeb1623:25:58UTC2018x86_64x86_64x86_64GNU/Linux)HOSTCCscripts/kconfig/mconf.oInfileincludedfromscripts/kc…

  • ios项目开发(天气预报项目):通过经纬度获取当前城市名称

    ios项目开发(天气预报项目):通过经纬度获取当前城市名称

    2021年11月23日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号