JVM参数调优

JVM参数调优

文章目录

      • JVM参数调优
        • 前言
        • JVM参数类型
        • 查看运行的Java程序,JVM参数是否开启,具体值为多少?
        • 题外话(坑题)
        • 查看JVM默认参数
        • 工作中常用的JVM基本配置参数
        • 查看堆内存
        • 打印JVM默认参数
        • 生活常用调优参数
        • GC垃圾收集
        • 参数大小设置参考

前言

如果你做过JVM调优和参数配置,那么如何盘点查看JVM系统默认值?

一般使用jps和jinfo进行查看(JPS:查看运行的Java进程,jinfo 是查看进程的具体信息)

-Xms:初始堆空间
-Xmx:堆最大值
-Xss:栈空间
-Xms 和 -Xmx最好调整一致,防止JVM频繁进行收集和回收
JVM参数类型
  • 标配参数(从JDK1.0 - Java12都在,很稳定)
  • -version
  • -help
  • java -showversion
    X参数(了解)
  • -Xint:解释执行
  • -Xcomp:第一次使用就编译成本地代码
  • -Xmixed:混合模式
    XX参数(重点)
    Boolean类型
    公式:-XX:+ 或者-某个属性 + 表示开启,-表示关闭
    Case:-XX:-PrintGCDetails:表示关闭了GC详情输出
    key-value类型
    公式:-XX:属性key=属性value
    不满意初始值,可以通过下列命令调整
    case:如何:-XX:MetaspaceSize=21807104:查看Java元空间的值
查看运行的Java程序,JVM参数是否开启,具体值为多少?

首先我们运行一个HelloGC的java程序

public class HelloGC {public static void main(String[] args) throws InterruptedException {System.out.println("hello GC");Thread.sleep(Integer.MAX_VALUE);}
}

然后使用下列命令查看它的默认参数

jps:查看java的后台进程
jinfo:查看正在运行的java程序

具体使用:

jps -l得到进程号
12608 com.moxi.interview.study.GC.HelloGC
15200 sun.tools.jps.Jps
15296 org.jetbrains.idea.maven.server.RemoteMavenServer36
4528
12216 org.jetbrains.jps.cmdline.Launcher
9772 org.jetbrains.kotlin.daemon.KotlinCompileDaemon

查看到HelloGC的进程号为:12608

我们使用jinfo -flag 然后查看是否开启PrintGCDetails这个参数

jinfo -flag PrintGCDetails 12608

得到的内容为

-XX:-PrintGCDetails

上面提到了,-号表示关闭,即没有开启PrintGCDetails这个参数

下面我们需要在启动HelloGC的时候,增加 PrintGCDetails这个参数,需要在运行程序的时候配置JVM参数
pFbJM80.md.png](https://imgse.com/i/pFbJM80)

然后在VM Options中加入下面的代码,现在+号表示开启

-XX:+PrintGCDetails

然后在使用jinfo查看我们的配置

jps -l
jinfo -flag PrintGCDetails 13540

得到的结果为

-XX:+PrintGCDetails

我们看到原来的-号变成了+号,说明我们通过 VM Options配置的JVM参数已经生效了

使用下列命令,会把jvm的全部默认参数输出

jinfo -flags *** 
题外话(坑题)

两个经典参数:-Xms 和 -Xmx,这两个参数 如何解释

这两个参数,还是属于XX参数,因为取了别名

-Xms 等价于 -XX:InitialHeapSize :初始化堆内存(默认只会用最大物理内存的64分1)

-Xmx 等价于 -XX:MaxHeapSize :最大堆内存(默认只会用最大物理内存的4分1)

查看JVM默认参数
  • -XX:+PrintFlagsInitial
  1. 主要是查看初始默认值

  2. 公式

java -XX:+PrintFlagsInitial -version

java -XX:+PrintFlagsInitial(重要参数)
pFbJ3KU.md.png

  1. -XX:+PrintFlagsFinal:表示修改以后,最终的值

         会将JVM的各个结果都进行打印如果有 := 表示修改过的, = 表示没有修改过的
    
工作中常用的JVM基本配置参数

pFbJ8rF.md.png

查看堆内存

查看JVM的初始化堆内存 -Xms 和最大堆内存 Xmx

public class HelloGC {public static void main(String[] args) throws InterruptedException {// 返回Java虚拟机中内存的总量long totalMemory = Runtime.getRuntime().totalMemory();// 返回Java虚拟机中试图使用的最大内存量long maxMemory = Runtime.getRuntime().maxMemory();System.out.println("TOTAL_MEMORY(-Xms) = " + totalMemory + "(字节)、" + (totalMemory / (double)1024 / 1024) + "MB");System.out.println("MAX_MEMORY(-Xmx) = " + maxMemory + "(字节)、" + (maxMemory / (double)1024 / 1024) + "MB");}
}

运行结果为:

TOTAL_MEMORY(-Xms) = 257425408(字节)、245.5MB
MAX_MEMORY(-Xmx) = 3790077952(字节)、3614.5MB

-Xms 初始堆内存为:物理内存的1/64 -Xmx 最大堆内存为:系统物理内存的 1/4

打印JVM默认参数

使用 -XX:+PrintCommandLineFlags 打印出JVM的默认的简单初始化参数

比如我的机器输出为:

-XX:InitialHeapSize=266376000 -XX:MaxHeapSize=4262016000 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
生活常用调优参数
  • -Xms:初始化堆内存,默认为物理内存的1/64,等价于 -XX:initialHeapSize

  • -Xmx:最大堆内存,默认为物理内存的1/4,等价于-XX:MaxHeapSize

  • -Xss:设计单个线程栈的大小,一般默认为512K~1024K,等价于 -XX:ThreadStackSize

  1. 使用 jinfo -flag ThreadStackSize 会发现 -XX:ThreadStackSize = 0

  2. 这个值的大小是取决于平台的

  3. Linux/x64:1024KB

  4. OS X:1024KB

  5. Oracle Solaris:1024KB

  6. Windows:取决于虚拟内存的大小

  • -Xmn:设置年轻代大小

  • -XX:MetaspaceSize:设置元空间大小

  1. 元空间的本质和永久代类似,都是对JVM规范中方法区的实现,不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存,因此,默认情况下,元空间的大小仅受本地内存限制。

  2. -Xms10m -Xmx10m -XX:MetaspaceSize=1024m -XX:+PrintFlagsFinal

  3. 但是默认的元空间大小:只有20多M

  4. 为了防止在频繁的实例化对象的时候,让元空间出现OOM,因此可以把元空间设置的大一些

  • -XX:PrintGCDetails:输出详细GC收集日志信息
  1. GC

  2. Full GC

GC日志收集流程图
pFbJYVJ.md.png

我们使用一段代码,制造出垃圾回收的过程

首先我们设置一下程序的启动配置: 设置初始堆内存为10M,最大堆内存为10M

-Xms10m -Xmx10m -XX:+PrintGCDetails

然后用下列代码,创建一个 非常大空间的byte类型数组

byte [] byteArray = new byte[50 * 1024 * 1024];

运行后,发现会出现下列错误,这就是OOM:java内存溢出,也就是堆空间不足

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat com.moxi.interview.study.GC.HelloGC.main(HelloGC.java:22)

同时还打印出了GC垃圾回收时候的详情


[GC (Allocation Failure) [PSYoungGen: 1972K->504K(2560K)] 1972K->740K(9728K), 0.0156109 secs] [Times: user=0.00 sys=0.00, real=0.03 secs] 
[GC (Allocation Failure) [PSYoungGen: 504K->480K(2560K)] 740K->772K(9728K), 0.0007815 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 480K->0K(2560K)] [ParOldGen: 292K->648K(7168K)] 772K->648K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0080505 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 648K->648K(9728K), 0.0003035 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 648K->630K(7168K)] 648K->630K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0058502 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
HeapPSYoungGen      total 2560K, used 80K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)eden space 2048K, 3% used [0x00000000ffd00000,0x00000000ffd143d8,0x00000000fff00000)from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 7168K, used 630K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)object space 7168K, 8% used [0x00000000ff600000,0x00000000ff69dbd0,0x00000000ffd00000)Metaspace       used 3510K, capacity 4500K, committed 4864K, reserved 1056768Kclass space    used 389K, capacity 392K, committed 512K, reserved 1048576K

问题发生的原因:

因为们通过 -Xms10m 和 -Xmx10m 只给Java堆栈设置了10M的空间,但是创建了50M的对象,因此就会出现空间不足,而导致出错

同时在垃圾收集的时候,我们看到有两个对象:GC 和 Full GC

GC垃圾收集
  • GC在新生代
[GC (Allocation Failure) [PSYoungGen: 1972K->504K(2560K)] 1972K->740K(9728K), 0.0156109 secs] [Times: user=0.00 sys=0.00, real=0.03 secs]

GC (Allocation Failure):表示分配失败,那么就需要触发年轻代空间中的内容被回收 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[PSYoungGen: 1972K->504K(2560K)] 1972K->740K(9728K), 0.0156109 secs]

参数对应的图为:
pFbJta9.md.png

  • Full GC垃圾回收
    Full GC大部分发生在老年代
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 648K->630K(7168K)] 648K->630K(9728K), [Metaspace: 3467K->3467K(1056768K)], 0.0058502 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 

pFbJaP1.md.png

规律:

[名称: GC前内存占用 -> GC后内存占用 (该区内存总大小)]

当我们出现了老年代都扛不住的时候,就会出现OOM异常

-XX:SurvivorRatio
调节新生代中 eden 和 S0、S1的空间比例,默认为 -XX:SuriviorRatio=8,Eden:S0:S1 = 8:1:1

加入设置成 -XX:SurvivorRatio=4,则为 Eden:S0:S1 = 4:1:1

SurvivorRatio值就是设置eden区的比例占多少,S0和S1相同

Java堆从GC的角度还可以细分为:新生代(Eden区,From Survivor区合To Survivor区)和老年代

-XX:SurvivorRatio
调节新生代中 eden 和 S0、S1的空间比例,默认为 -XX:SuriviorRatio=8,Eden:S0:S1 = 8:1:1

加入设置成 -XX:SurvivorRatio=4,则为 Eden:S0:S1 = 4:1:1

SurvivorRatio值就是设置eden区的比例占多少,S0和S1相同

Java堆从GC的角度还可以细分为:新生代(Eden区,From Survivor区合To Survivor区)和老年代

pFbJd8x.md.png

  • eden、SurvivorFrom复制到SurvivorTo,年龄 + 1

首先,当Eden区满的时候会触发第一次GC,把还活着的对象拷贝到SurvivorFrom去,当Eden区再次触发GC的时候会扫描Eden区合From区域,对这两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域(如果对象的年龄已经到达老年的标准,则赋值到老年代区),通知把这些对象的年龄 + 1

  • 清空eden、SurvivorFrom

然后,清空eden,SurvivorFrom中的对象,也即复制之后有交换,谁空谁是to

  • SurvivorTo和SurvivorFrom互换

最后,SurvivorTo和SurvivorFrom互换,原SurvivorTo成为下一次GC时的SurvivorFrom区,部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认为15),最终如果还是存活,就存入老年代
pFbJ0xK.md.png

-XX:NewRatio(了解)
配置年轻代new 和老年代old 在堆结构的占比

默认: -XX:NewRatio=2 新生代占1,老年代2,年轻代占整个堆的1/3

-XX:NewRatio=4:新生代占1,老年代占4,年轻代占整个堆的1/5,NewRadio值就是设置老年代的占比,剩下的1个新生代

新生代特别小,会造成频繁的进行GC收集

-XX:MaxTenuringThreshold
设置垃圾最大年龄,SurvivorTo和SurvivorFrom互换,原SurvivorTo成为下一次GC时的SurvivorFrom区,部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认为15),最终如果还是存活,就存入老年代

这里就是调整这个次数的,默认是15,并且设置的值 在 0~15之间

查看默认进入老年代年龄:jinfo -flag MaxTenuringThreshold 17344

-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻对象不经过Survivor区,直接进入老年代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大的值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概念

参数大小设置参考

pFbaVtH.md.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593653.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【测开求职】校招生在面测开前需要了解的信息

博主在2021年拿到了字节测开实习的offer,实习时长4个月,并于2023年秋招拿到了字节测开的校招offer,仅以本专栏记录对该岗位的所思所想。 目录 1. 测试开发需要做什么工作2. 为什么选择测试开发3. 测试开发不如开发吗4. 如何准备测试开发 1. …

华为“天才少年”4万字演讲:现在的AI技术要么无趣,要么无用

华为“天才少年”4万字演讲:现在的AI技术要么无趣,要么无用|钛媒体AGI© AI科技组 (图片来源:unsplash) 近期,一篇4万字的演讲风靡于国内人工智能(AI)学术圈。 原…

基于 Rust 标准库 API 使用 200 行代码实现 Http 1.1 协议简易服务

1. 背景 早在之前学过一波 Rust,但是由于没用武之地,没过多久又荒废了,最近想捡起来下。刚好看见有群里小伙伴说学习 Http 网络协议太难怎么办?其实很多技术都是相通的,只要你理解了技术的本质就可以自己实现它&#…

Midjourney艺术家分享|By Moebius

Moebius,本名让吉拉德(Jean Giraud),是一位极具影响力的法国漫画家和插画师,以其独特的科幻和幻想风格而闻名于世。他的艺术作品不仅在漫画领域内受到高度评价,也为电影、时尚和广告等多个领域提供了灵感。…

备考ICA----Istio实验16---HTTP流量授权

备考ICA----Istio实验16—HTTP流量授权 1. 环境准备 kubectl apply -f istio/samples/bookinfo/platform/kube/bookinfo.yaml kubectl apply -f istio/samples/bookinfo/networking/bookinfo-gateway.yaml访问测试 curl -I http://192.168.126.220/productpage2. 开启mtls m…

Kubernetes(K8s)技术解析

1. K8s简介 Kubernetes(简称K8s)是一个开源的容器编排平台,旨在简化容器化应用程序的部署、扩展和管理。为开发者和运维人员提供了丰富的功能和灵活的解决方案,帮助他们更轻松地构建、部署和管理云原生应用程序。以下是关于Kubern…

Linux:Centos9:配置固定ip

centos9的网卡位置移动到了 /etc/NetworkManager/system-connections/ 下面 查看网卡 ifconfig 当前有两块网卡,我要去配置ens160的一个固定的ip,让其ip为192.168.6.20/24,网关为192.168.6.254.dns为:1.1.1.1 vim /etc/Netwo…

GPT3, llama2, InternLM2技术报告对比

GPT3(September 22, 2020)是大语言应用的一个milestone级别的作品,Llama2(February 2023)则是目前开源大模型中最有影响力的作品,InternLM2(2023.09.20)则是中文比较有影响力的作品。…

基于jsp+Spring boot+mybatis的图书管理系统设计和实现

基于jspSpring bootmybatis的图书管理系统设计和实现 博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获…

基于SpringBoot Vue宠物领养系统

一、📝功能介绍 基于SpringBoot Vue宠物领养系统 角色:管理员、用户 当游客打开系统的网址后,首先看到的就是首页界面。在这里,游客能够看到宠物领养救助平台的导航条显示首页、宠物招领、宠物认领、 宠物论坛、宠物资讯、后台管…

神经网络汇聚层

文章目录 最大汇聚层平均汇聚层自适应平均池化层 最大汇聚层 汇聚窗口从输入张量的左上角开始,从左往右、从上往下的在输入张量内滑动。在汇聚窗口到达的每个位置,它计算该窗口中输入子张量的最大值或平均值。计算最大值或平均值是取决于使用了最大汇聚…

kafka集群介绍+部署Filebeat+Kafka+ELK

一、消息队列 1、为什么需要消息队列(MQ) 主要原因是由于在高并发环境下,同步请求来不及处理,请求往往会发生阻塞。比如大量的请求并发访问数据库,导致行锁表锁,最后请求线程会堆积过多,从而触…