JVM调优篇
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。
基础概念
- 一般JVM调优,重点在于调整JVM堆大小、调整垃圾回收器
- jvm调优的目的是,减少full gc、降低gc停顿时间、提高吞吐量;调优的顺序=“提高吞吐量”>“降低gc停顿时间”;在满足吞吐量的前提下,再降低gc停顿时间;若不能同时满足以上,则选择最适合系统的一种调优结果
JVM调优常用参数
- -Xmx1024m:最大堆内存,当物理内存不超过192m时最大堆内存为物理内存的一半,否则为物理内存的四分一
- -Xms1024m:最小堆内存,一般设置为与-Xmx同等值
- -XX:+PrintGCDetails:输出gc详细日志
- -XX:+PrintGCTimeStamps或-XX:+PrintGCDateStamps:输出gc信息时带上时间戳
- jcmd:专用于查看JVM状态,可以查看正在运行的进程,会显示出进程号

- jmap -heap 10864:查看进程号为10864的进程的堆使用情况
具体参数如下:
F:\Iwebapp\demo-test>jmap -heap 10864
Attaching to process ID 10864, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.65-b01
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0 //空余堆内存最小百分比,HeapFreeRatio=空闲堆内存的百分比=现有空闲堆内存/总共对内存*100,当MinHeapFreeRatio<HeapFreeRatio时,在每次垃圾回收之后需要进行对扩容
MaxHeapFreeRatio = 100 //空余堆内存最大百分比
MaxHeapSize = 1044381696 (996.0MB) //996.0MB=最大堆内存无物理内存1/4=4G*1/4约等于1G
NewSize = 22020096 (21.0MB) //年轻代堆内存的初始大小
MaxNewSize = 348127232 (332.0MB) //年轻代堆内存的允许最大值,因为年轻代:老年代=1:2,所以年轻代最大=996*1/3=332
OldSize = 45088768 (43.0MB)
NewRatio = 2 //老年代:年轻代=2:1
SurvivorRatio = 8 //年轻代中Eden区:Survivor区=8:2,Survivor区=SurvivorFrom区+SurvivorTo区=1+1=2
MetaspaceSize = 21807104 (20.796875MB) //jdk1.8之后使用的元空间默认大小
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB //jdk1.8之后使用的元空间的最大值
G1HeapRegionSize = 0 (0.0MB) //若使用G1垃圾回收器,JVM把堆内存每个多个大小相等的区域,指定每个区域的大小
Heap Usage:
PS Young Generation
Eden Space: //年轻代的使用情况
capacity = 289931264 (276.5MB)
used = 160612016 (153.1715545654297MB)
free = 129319248 (123.32844543457031MB)
55.39658392963099% used
From Space: //SurvivorFrom区的使用情况
capacity = 5767168 (5.5MB)
used = 65536 (0.0625MB)
free = 5701632 (5.4375MB)
1.1363636363636365% used
To Space: //SurvivorTo区的使用情况
capacity = 5242880 (5.0MB)
used = 0 (0.0MB)
free = 5242880 (5.0MB)
0.0% used
PS Old Generation //老年代的使用情况
capacity = 37748736 (36.0MB)
used = 13700064 (13.065399169921875MB)
free = 24048672 (22.934600830078125MB)
36.29277547200521% used
监控JVM
实战源码:以demo-test工程为例,用gcviewner和jdk内置的监控jvm命令来做jvm调优
package com.example.demo;
import com.example.util.ThreadTest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoTestApplication {
public static void main(String[] args) {
SpringApplication.run(DemoTestApplication.class, args);
ThreadTest.testJVM();
}
}
public class ThreadTest {
public static void main(String[] args) {
testJVM();
}
public static void testJVM(){
//匿名内部类重写Runnable的run方法可以写成箭头函数:()->{run方法的内容}
//1000ms后每50ms执行创建1个线程,每个线程150*512*1024byte=150*512*1024B=150*512k=150*0.5M=75M,1s内最多1000/50=20个线程,则1s内最大占用内存=75*20=150M
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(()->{
new Thread(()->{
for(int i=1;i<=150;i++){
byte[] b=new byte[1024*512];//0.5M
}
System.out.println(Thread.currentThread().getName()+"已分配512k内存...");
}).start();
},1000,50,TimeUnit.MILLISECONDS);
}
在target目录下【java -jar -Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】启动jar包或者直接在idea中添加【-Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps】启动springboot启动类,以下用gcviewner监控JVM :
- gcviwner
gcviwner是一款可以监控GC日志的工具,前提是要拿到gc日志,gcviwner用法可参考【https://github.com/chewiebug/GCViewer】 ,命令 【java -jar gcviewer-1.37-SNAPSHOT.jar】启动gcviwner,并导入gc.log日志,如下,



上中下三张图,由上图可知吞吐量为74.26%,一般可以达到90%以上,红线是堆的实时总内存,蓝线是堆的实时已使用内存,灰色为young gc,黑色为full gc,可知灰色的线太密集=young gc频繁,黑色的线也是太密集=full gc频繁;full gc总数为296,一般可以把full gc降到个位数;
由中图可知最大停顿时间比较大,达到了892ms,一般可调优到几十毫秒级别;
有下图可看到young gc和full gc的情况,full gc次数296,比较频繁;同时元空间metadata区域过小,可以适当调大
由上,把metadata调为64M,执行【java -jar -XX:MetaspaceSize=64m -Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】重新启动jar包:


可知full gc次数还是比较多、最大停顿时间也比较长、吞吐量也低,尝试着增大'最大堆内存',执行【java -jar -XX:MetaspaceSize=64m -Xloggc:gc.log -Xmx100m -Xms100m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】重新启动jar包:


可知full gc次数变少了(黑线少了,0次)、最大停顿时间也短了(94.65ms,到了十几毫秒级别)、吞吐量也高了(93.83%)
至此,调优基本满足上面的【减少full gc、降低gc停顿时间、提高吞吐量】的要求。
下面是jdk内置的jvm监控命令
- jstat命令
jstat命令用于监视虚拟机的运行状态,命令格式【jstat -参数命令 进程号 间隔毫秒数 总输出次数】,主要参数项:

//每1000ms统计一次demo-test-0.0.1.jar的gc信息
jstat -gc $(jcmd | grep "demo-test-0.0.1.jar" | awk '{print $1}') 1000

S0C、S1C、S0U、S1U:C是总量,U是使用量,代表S0(survivorFrom区)和S1(survivorTo区)的总量与使用量
EC、EU:Eden区总量与使用量
OC、OU:Old区总量与使用量
MC、MU: Metaspace区(元空间)总量与使用量
YGC、YGCT:young gc的次数与时间
FGC、FGCT:full gc的次数与时间<
GCT:总的GC时间
//每1000ms统计一次进程ID为10492的gc信息,共统计10次数结束统计
jstat -gc 10492 10

- jps
jps可以查看正在运行的java进程,命令格式【jsp 参数】,主要参数项:

【jsp -l】查看具体的包名

- jinfo
可以查看启动jar包时未显式指定的系统默认值,以及动态修改这些默认值,命令格式【jinfo -flag 默认的参数 进程id】,查看【年轻代:老年代】的内存比例:

- jmap
jmap查看java内存信息,命令格式【jmap -参数 进程id】,参数项:

实例如上:【jmap -heap 10864】查看进程号为10864的进程的堆使用情况
- jstack
jstack是一个非常有用的命令,可以查看正在运行的线程的堆栈信息,比如查看后天没有相应的线程在做些什么,在等待什么资源,命令格式【jstack 参数项 进程号】,主要参数项如下:

//查看进程的堆栈及锁的信息
jstack -l 10220

图中线程状态是很重要的一个要素:

CMS收集器和G1收集器的调优
启动各种垃圾收集器
| 参数 | 说明 |
|---|---|
| -XX:+UseParallelGC | 新生代使用并行回收收集器 |
| -XX:+Use ParalleloldGC | 老年代使用并行回收收集器 |
| -XX:ParallelGCThreads | 设置用于垃圾回收的线程数 |
| -XX:+UseAdaptiveSizePolicy | 打开自适应GC策略 |
CMS和G1的调优
- cms是分代收集算法中老年代的算法(用标记整理算法),G1却适用于年轻代和老年代,故G1可以采用复制算法不会导致内存碎片,而cms不能采用年轻代的复制算法而导致有内存碎片
- G1是由一个个区域块组成的,即使有碎片也只会影响某个区域块,不会影响整个堆
- cms采用老年代标记整理算法,需要扫描整个表来标记整理,故存在停顿(即使它是并发);G1的停顿取决于需要收集的'区域块'个数,而不用等整个堆空间,所以g1的停顿时间比cms少
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!
JVM调优篇的更多相关文章
- jvm系列(七):jvm调优-工具篇
16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗 ...
- JVM调优-工具篇
原文地址 16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一 ...
- <JVM下篇:性能监控与调优篇>补充:使用OQL语言查询对象信息
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- <JVM下篇:性能监控与调优篇>补充:浅堆深堆与内存泄露
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- <JVM下篇:性能监控与调优篇>03-JVM监控及诊断工具-GUI篇
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- <JVM下篇:性能监控与调优篇>01-概述篇-02-JVM监控及诊断工具-命令行篇
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- Jvm调优理论篇
Jvm实战调优 OOM(Out Of Memory) 内存溢出错误 ps:由于Java虚拟机有许多实现,本文主要阐述的是OpenJDK的HotSpot虚拟机,JDK版本是8. 一.首先要明白造成OOM ...
- 阿里面试100%问到,JVM性能调优篇
JVM 调优概述 性能定义 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收集 ...
- jvm系列(四):jvm调优-命令篇
运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...
随机推荐
- 【深度学习 01】线性回归+PyTorch实现
1. 线性回归 1.1 线性模型 当输入包含d个特征,预测结果表示为: 记x为样本的特征向量,w为权重向量,上式可表示为: 对于含有n个样本的数据集,可用X来表示n个样本的特征集合,其中行代表样本,列 ...
- 27.Java 飞机游戏小项目
开篇 游戏项目基本功能开发 飞机类设计 炮弹类设计 碰撞检测设计 爆炸效果的实现 其他功能 计时功能 游戏项目基本功能开发 这里将会一步步实现游戏项目的基本功能. 使用 AWT 技术画出游戏主窗口 A ...
- C#中的类型转换-自定义隐式转换和显式转换
目录 前言 基础知识 示例代码 实际应用 问题 答案 报错 用户定义的转换必须是转换成封闭类型,或者从封闭类型转换 参考 其他 应用和设计 读音 参考 前言 有时我们会遇到这么一种情况:在json数据 ...
- java 集合及其线程安全 及其 set linkedList map table 区别
早在jdk的1.1版本中,所有的集合都是线程安全的.但是在1.2以及之后的版本中就出现了一些线程不安全的集合,为什么版本升级会出现一些线程不安全的集合呢?因为线程不安全的集合普遍比线程安全的集合效率高 ...
- MyBatis 框架适用场合?
1.MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案. 2.对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是 不错的选择.
- 学习zabbix(六)
实验环境 实验用2到2台机器,实验所用机器系统环境如下,可以看到2台机器的主机名和IP地址 ? 1 2 3 4 5 6 7 8 9 10 [root@linux-node1 ~]# cat /etc/ ...
- 学习openstack(三)
一.OpenStack初探 1.1 OpenStack简介 OpenStack是一整套开源软件项目的综合,它允许企业或服务提供者建立.运行自己的云计算和存储设施.Rackspace与NASA是最初 ...
- Python的数据基础库Numpy怎样对数组进行排序
Numpy怎样对数组排序 Numpy给数组排序的三个方法: numpy.sort:返回排序后数组的拷贝 array.sort:原地排序数组而不是返回拷贝 numpy.argsort:间接排序,返回的是 ...
- 从零开始画自己的DAG作业依赖图(四)--节点连线优化版
概述 上个版本简单的连线在一些复杂场景,尤其层级比较多,连线跨层级比较多的情况下,会出现线条会穿过矩形的情况,这一讲就是在这个基础上,去优化这个连线. 场景分析 在下面几种情况下,简单版本的画法已经没 ...
- 在原生CSS中使用变量
本文首发于我的博客 一直以来,CSS作为一种申明式的样式标记语言,很难像如javascript等命令式编程语言一样通过定义和使用变量的方式来维护和追踪某些状态.后来随着scss,less等CSS预处理 ...