22_JVM参数调优

题目2:你说你做过JVM调优和参数配置,请问如何盘点查看 JVM系统默认值

使用 jps 和 jinfo 进行查看

# 调整JVM初始化参数(-Xms 和 -Xmx最好调整一致,防止JVM频繁进行收集和回收)
-Xms:初始堆空间
-Xmx:堆最大值
-Xss:栈空间

JVM参数类型

标配参数

从JDK1.0 - Java12都在,很稳定

  • -version
  • -help
  • java -showversion

在这里插入图片描述


X参数(了解)

  • -Xint:解释执行
  • -Xcomp:第一次使用就编译成本地代码
  • -Xmixed:混合模式

在这里插入图片描述


XX参数(重点)

Boolean类型

公式:

  • -XX:+ 或者-某个属性
  • +表示开启,-表示关闭

Case

-XX:-PrintGCDetails:表示关闭了GC详情输出

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

查看运行的Java程序,JVM参数是否开启,具体值为多少?

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

/**
 * @Author: xj0927
 * @Date Created in 2021-01-27 13:29
 */
public class HelloGC {

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

在这里插入图片描述


然后查看java的后台进程:

# 得到进程号
jps -l

在这里插入图片描述


然后查看是否开启PrintGCDetails这个参数:

# + 表示开启,-号 表示没开启
jinfo -flag PrintGCDetails 9936

在这里插入图片描述

结果表明:-号表示关闭,即没有开启PrintGCDetails这个参数


最后:需要在启动HelloGC的时候,增加 PrintGCDetails这个参数,需要在运行程序的时候配置JVM参数

在这里插入图片描述

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

-XX:+PrintGCDetails

在这里插入图片描述


重启启动程序,使用 jps -l得到进程号,使用jinfo -flag PrintGCDetails 进程号得到配置结果:

-XX:+PrintGCDetails

在这里插入图片描述

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


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

jinfo -flags 进程号

在这里插入图片描述


KV设值类型

-XX:属性key=值value

Case

-XX:MetaspaceSize=128m 调整元空间大小

-XX:MaxTenuringThreshold=15 调整存活年龄

还是刚刚那个程序,首先我们查看默认的元空间大小:

# 查看进程号
jps -l

# 查看默认空间(此时是键值对类型)
jinfo -flag MetaspaceSize 11080

在这里插入图片描述


配置元空间大小:

# 配置元空间大小为1024m
-XX:MetaspaceSize=1024m

在这里插入图片描述

重新启动程序,查看:

在这里插入图片描述

配置生效!


同样操作:配置存活年龄

-XX:MaxTenuringThreshold=10

在这里插入图片描述
在这里插入图片描述


jinfo:如何查看当前程序运行的配置

jinfo -flag 某个参数 pid

或者

jinfo -flags pid 显示所有参数

Case1
# 查看堆内存初始化大小
jinfo -flag InitialHeapSize  15276

在这里插入图片描述


Case2
# 查看全部配置信息
jinfo -flags 15276
# 结果:
VM Flags:
-XX:CICompilerCount=12 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4278190080 -XX:MaxNewSize=1426063360
-XX:MetaspaceSize=1073741824 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+
UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndivi
dualAllocation -XX:+UseParallelGC

题外话(坑题)

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

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

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

与机器本身配置有关:

在这里插入图片描述

我们进行重新配置:

# 设置初始化大小200m,最大3g
-Xms200m -Xmx3g

在这里插入图片描述
在这里插入图片描述


查看JVM默认参数

-XX:+PrintFlagsInitial

方式一:查看初始默认值

公式:

  • java -XX:+PrintFlagsInitial -version
  • java -XX:+PrintFlagsInitial(重要参数)

在这里插入图片描述


方式二:查看修改后的,最终的值(可能是JVM,也可能是人为修改)

公式:

  • -XX:+PrintFlagsFinal -version

在这里插入图片描述

会将JVM的各个结果都进行打印

如果有 := 表示修改过的, = 表示没有修改过的

以初始化堆内存为例:我的机器是16G内存,所以JVM会划内存的1/64给堆初始化,即270m左右

在这里插入图片描述
在这里插入图片描述

实例2:运行java命令的同时打印出参数

java -XX:+PrintFlagsFinal -Xss128k javaClass

方式三:查看一些常见的参数

-XX:+PrintCommandLineFlags

 java -XX:+PrintCommandLineFlags -version

在这里插入图片描述

该命令主要是用来查看当前使用的垃圾回收器


工作中常用的JVM基本配置参数

题目3:用过的JVM常用基本配置参数有哪些?

知识复习:

在这里插入图片描述


查看堆内存

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

代码方式查看:

/**
 * @Author: xj0927
 * @Date Created in 2021-01-27 13:29
 */
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");
    }
}

运行结果:

在这里插入图片描述

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


常用参数

-Xms

-Xms:初始化堆内存,默认为物理内存的1/64,

等价于 -XX:initialHeapSize


-Xmx

-Xmx:最大堆内存,默认为物理内存的1/4,

等价于-XX:MaxHeapSize


-Xss

-Xss:设计单个线程栈的大小,一般默认为512K~1024K,

等价于 -XX:ThreadStackSize

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

原因:

# 官网解释(JDK8)
Linux/x64:1024KB
OS X:1024KB
Oracle Solaris:1024KB
Windows:取决于虚拟内存的大小

-XX:MetaspaceSize

设置元空间大小

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。

元空间与永久代的最大区别在于,永久代在虚拟机中(占用堆内存),而元空间在本地内存中(占用物理内存)。

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

# 查看默认配置大小(大约21m)
java -XX:+PrintFlagsFinal -version

# 设置元空间大小
-XX:+MetaspaceSize=1024m

-XX:+PrintGCDetails

输出GC收集日志信息

分为:

  • GC
  • Full GC

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

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

-Xms10m -Xmx10m -XX:+PrintGCDetails

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

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

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

在这里插入图片描述

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

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

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


GC

GC垃圾回收发生在新生代


参数图:

在这里插入图片描述

# GC信息(GC (Allocation Failure):表示分配失败,那么就需要触发年轻代空间中的内容被回收)
[GC (Allocation Failure) [PSYoungGen: 1580K->504K(2560K)] 1580K->764K(9728K), 0.0167268 secs] [Times: user=0.00 sys=0.00, real=0.02 secs] 

Full GC垃圾回收

Full GC大部分发生在养老区

参数图:

在这里插入图片描述

# Full GC
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 592K->574K(7168K)] 592K->574K(9728K), [Metaspace: 3158K->3158K(1056768K)], 0.0040996 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 

规律:

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

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


综合案例

VM综合配置:

-Xss1024k -Xms200m -Xmx4g -XX:MetaspaceSize=1024m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC
  • -Xss1024k 栈大小
  • -Xms200m 堆初始化大小
  • -Xmx4g 堆最大值
  • -XX:MetaspaceSize=1024m 元空间大小
  • -XX:+PrintCommandLineFlags 打印常用配置
  • -XX:+PrintGCDetails 打印日志信息
  • -XX:+UseSerialGC 使用垃圾回收器的名称(串行回收器)

在这里插入图片描述


-XX:SurvivorRatio

调节新生代中eden 和 S0、S1的空间比例,

默认为 -XX:SuriviorRatio=8,Eden:S0:S1 = 8:1:1

在这里插入图片描述

我们设置如下参数:

# 分配堆内存为10m(此时新生代大约占2~3m)
-Xms10m -Xmx10m  -XX:+PrintGCDetails

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

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

-Xms10m -Xmx10m  -XX:+PrintGCDetails -XX:SurvivorRatio=4

在这里插入图片描述


-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 进程号

# 设置年龄:
 -XX:MaxTenuringThreshold=15

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值