JVM调优,调的是什么?目的是什么?

转载:https://mp.weixin.qq.com/s/8CEczEdoQ2T5QP3EXKKE6Q

在这里插入图片描述

jvm是java语言可以跨平台运行的基础

jvm 是什么?

jvm是一个可以运行字节码文件的机器;

jvm调优调的是什么?

调整jvm内存模型中的参数,以及GC垃圾回收器的选择,甚至可以选择使用哪种垃圾回收算法;

那么调优的目的是什么?

调优调的是: 减少GC 的次数,以及GC的STW (Stop-the-World,简称STW)时间,

这里的GC 大多数指FULL GC 。

STW (Stop-the-World,简称STW) 暂停原因:STW的主要目的是为了在垃圾回收期间保证应用程序的一致性。当Java虚拟机启动垃圾回收时,它会暂停所有的应用线程,以防止在垃圾回收期间发生数据竞争或并发错误。

参考:GC 的背景与一般原理:

https://baijiahao.baidu.com/s?id=1772465834635090589&wfr=spider&for=pc

当然minor gc 可能时间会非常长,不过这个情况较为特殊,之后文中会说;

在这里插入图片描述

大概步骤为

• java源文件编译为.class文件

• .class文件被各种平台版本的jvm编译为本地机器码(字节码)

• 类加载机制将这些字节码加载后,放到运行时数据中(内存模型中)

• 字节码执行器,通过内存中的入栈出栈执行运行时数据区中(内存模型中)这些字节码

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

jvm内存模型

● 堆: 存放对象实例 常量池

● 方法区: 方法信息头,静态变量,常量

● java虚拟机栈: 对象的引用,指针,八大基本类型 局部变量

● 本地方法栈: native保留方法运行时候的内存空间

● 程序计数器: 存放执行字节码的行号指示器 (字节码指令的地址)

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

1. 首先new 一个对象的时候,对象一般会在堆中开辟一块内存存储

2. 然后这个线程结束,这个对象不再被引用之后,就会被纳入到年轻代,当其中的一块s区域满了,发生轻gc,也就是会发生stw;

3. 多种情况会导致对象进入老年代: 例如 一个对象的分代年龄大于15; 对象的整体大小大于s0/s1区域的50% ,不会放入s区,直接进入老年代 等等;

4. 分代年龄: 在s区域中的对象,每经过一次轻gc,分代年龄加1;

5. 轻gc处理对象的方式: 一部分被加入到老年代,大多数都是从一个s区域复制到另个一s区域(标记复制算法)

6. s区域中的两块区域,总有一块是空的;

在这里插入图片描述

1. 与轻gc 类似,FULL GC 是发生在老年代的gc

2. stw 是 stop the word,所有用户线程都会停止,现象例如: 你在淘宝添加一个物品到购物车,卡住了;

3. 发生full gc 与轻gc类似,也就是老年代空间被填满了,必须进行垃圾回收,将无用对象全部移除,释放空间

4. 如果释放的空间不够,程序仍然在申请大量的内存,那么此时会发生 oom;

5. full gc 一般采用 可达性算法回收(自行百度);

可达性算法是一种用于判断对象是否可被访问的算法,它能够从一个或多个起始对象出发,找到所有可以通过引用链访问到的对象,并将其标记为可达。

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

可以看到垃圾回收器一般不采用单独的一个算法实现 JDK9 前,我们会在 CMS 和

G1 间选择,对于大概 4GB 到 6GB 以下的堆内存,CMS 一般能处理得比较好,而对于更大的堆内存,

可重点考察一下 G1 。

在这里插入图片描述

 -XX:+UseG1GC
启用 G1 垃圾回收器
-XX:InitiatingHeapOccupancyPercent=<45>
当整个 Java 堆的占用达到参数的值时,开始并发标记阶段
-XX:MaxGCPauseMillis=200
G1 暂停时间目标 ( >0 的毫秒数)
-XX:NewRatio=n
新生代与老生代 (new/old generation) 的大小比例 (Ratio). 默认值为 2
-XX:SurvivorRatio=n
Eden/Survivor 空间大小的比例 (Ratio). 默认值为 8
-XX:MaxTenuringThreshold=n
提升年老代的最大临界值 (tenuring threshold). 默认值为 15
-XX:ParallelGCThreads=n
设置垃圾收集器在并行阶段使用的线程数,默认值随 JVM 运行的平台不同而不同
-XX:ConcGCThreads=n
并发垃圾收集器使用的线程数量。 默认值随 JVM 运行的平台不同而不同
-XX:G1ReservePercent=n
作为空闲空间的预留内存百分比,以降低目标空间溢出的风险。默认值是 10%
-XX:G1HeapRegionSize=n
指定每个 Region 的大小。默认值将根据 heap size 算出最优解。最小值为 1Mb, 最大值为 32Mb

在这里插入图片描述

//常见配置汇总 
//堆设置 
-Xms:初始堆大小 
-Xmx:最大堆大小 
-XX:NewSize=n:设置年轻代大小 
-XX:NewRatio=n:设置年轻代和年老代的比值.:3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值.注意Survivor区有两个.:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 
-XX:MaxPermSize=n:设置持久代大小
-XX:MetaspaceSize:设置元空间大小
-XX:MaxMetaspaceSize:设置元空间最大大小
-Xss128k: 设置每个线程的堆栈大小。
//收集器设置 
-XX:+UseSerialGC:设置串行收集器 
-XX:+UseParallelGC:设置并行收集器 
-XX:+UseParalledlOldGC:设置并行年老代收集器 
-XX:+UseConcMarkSweepGC:设置并发收集器
//垃圾回收统计信息 
-XX:+PrintGC 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-Xloggc:filename
//并行收集器设置 
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数.并行收集//线程数. 
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间 
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比.公式为1/(1+n)
//并发收集器设置 
-XX:+CMSIncrementalMode:设置为增量模式.适用于单CPU情况. 
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数.并行收集线程数.
-XX:+CMSParallelRemarkEnabled:并发清理

在这里插入图片描述

1. jmap jmap使用 ()

2. jstack jstack使用 ()

3. 阿里arhtas(阿尔萨斯)百度即可;

下载,运行 arthas Arthas (阿尔萨斯)是阿里巴巴开源的 Java 诊断工具

● 线程占用过高原因: thread pid

● 死锁信息: thread -b

● 查看当前代码: jad 文件名称

在这里插入图片描述

通过看此文章不会让你知道具体怎么调优,但是应该知道如果调优的大体学习路线。

在这里插入图片描述

调优的目的是为了减少full gc 的次数和时间,尽量通过minor gc处理;

问题如下: 我现在有 8核64G的一个服务器,上面运行的程序不是BAT那种级别的,但是也不小;

问题: 堆内存可以设置很大,为了尽量通过轻gc解决,是不是年轻代设置的越大越好?

答案是否定的,因为当年轻代足够大之后,发生minor gc 的时候,也需要stw ,这个时间也会非常久,

所以还是需要做合适大小的配置,这也就是我们为什么要调优的原因;

合适的大小才最重要 !!!

在这里插入图片描述

命令: JPS

1 查看java进程 jps

在这里插入图片描述

2 设置jvm参数 -Xms512m -Xmx512m (堆内存)

在这里插入图片描述

3 查看当前进程的具体内存分配 jmap -heap 22096

在这里插入图片描述

堆的总大小为512m NewRatio 新生代与老年代的比例为1:2 则: 新生代为 170m 老年代为 340m

由于eden: s0 : s1 等于 8:1:1 所以 s0=s1 大概等于17m左右,剩余为eden区域大小 大概为134m左右

但是出现的结果不一致 s0 =s1 大概为 21m eden区域大概为 129m。

与正常结果差4,知道为啥嘛?

• 再次加大堆大小为 1024m 和 2048m 结果分别为: eden: s0 : s1 为271:34:34 与正常结果s0差 8 eden: s0 : s1 为512:85:85 与正常结果s0差16

• 设置jvm参数 相互冲突

• 设置堆大小为 1024m 且设置新生代大小为500m

-Xms1024m -Xmx1024m -XX:NewSize=500m

在这里插入图片描述

1 在不考虑新生代大小的情况下,正常来说结果应为 eden: s0 : s1 为271:34:34 与正常结果s0差 8

2 由于设置了新生代大小,所有新生代为固定大小 500m

3 那么 eden: s0 : s1 仍为8:1:1,所以大小应该为 400:50:50 4 由于与结果相差8 ,所以大概应该为386:58:58

上图验证结果:

在这里插入图片描述

我真的是,无法把握它的准确大小了(需要结合新生代大小NewRatio)及根据

Eden:s0:s1(8:1:1) 比例计算出合适的或相近的初始化堆大小。

调优步骤总结:

1、启动需要调优的项目

在这里插入图片描述

2、通过命令JPS查找 需要调优的项目进程号

在这里插入图片描述

3 查看当前进程的具体内存分配 jmap -heap 27764

在这里插入图片描述
NewRatio = 2
MaxHeapSize = 4236247040 (4040.0MB)
NewSize = 88604672 (84.5MB)
MaxNewSize = 1411907584 (1346.5MB)
OldSize = 177733632 (169.5MB)
NewRatio = 2 (NewSize:OldSize=1:2)
SurvivorRatio = 8 (Eden:s0:s1=8:1:1)

Eden Space:
capacity = 127926272 (122.0MB)
used = 93514976 (89.18283081054688MB)
free = 34411296 (32.817169189453125MB)

From Space:
capacity = 11010048 (10.5MB)
used = 10662040 (10.168113708496094MB)
free = 348008 (0.33188629150390625MB)
96.83917817615327% used

To Space:
capacity = 11534336 (11.0MB)
used = 0 (0.0MB)
free = 11534336 (11.0MB)
0.0% used

PS Old Generation
capacity = 101711872 (97.0MB)
used = 8171424 (7.792877197265625MB)
free = 93540448 (89.20712280273438MB)
8.033894017799613% used

• 设置堆大小为 1024m 且设置新生代大小为364m

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

经过此番学习,对于jvm内存模型,代码运行,对象流转,内存分配有了更高层次认知,对于jvm调优,

为什么要调优有清晰的认知; 改jvm参数不难,难的是你要知道参数的大小的计算; 要明白参数大小的由来.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值