听说 JVM 性能优化很难?今天我小试了一把!
文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。

对于 Java 开发的同学来说,JVM 性能优化可以说是比较难掌握的知识点。这不仅因为 JVM 性能优化需要掌握晦涩难懂的 JVM 知识,还因为 JVM 性能优化很难有使用场景。这导致了许多人对 JVM 性能优化不熟悉,感觉就像是空中楼阁的天物一样不可触及。这几天工作中做了一次 JVM 性能优化,我想这对于 JVM 调优的初学者会有较大帮助。
背景
我们都知道 JVM 分为了新生代和老年代,并且我们在启动应用的时候都会配置对应的参数,为应用程序运行的 JVM 调整内存大小。但我们都知道,很多时候我们都只是大致估计一个数,随便填填,然后就上线了。
作者所在的公司同样存在这种情况,JVM 内存大小基本上都设得挺大的,毕竟内存大总比内存溢出好,因此就造成了不少的内存浪费。所以作者收到的任务就是对所有的应用进行一次排查,调整合适的内存参数,优化 JVM 的性能。
调优实战
要对应用进行 JVM 性能调优,那么首先得知道其运行的情况。这就像去医院看医生,去开药之前需要医生先望闻问切一样。在 Java 中,有很多方式可以观察到 JVM 的内部情况,例如 JDK 提供的各种命令工作。作者所在公司使用的是 Prometheus 进行监控,因此我们可以直接在 Prometheus 上看到应用的 JVM 运行情况。
文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。
Prometheus 面板中与 JVM 相关的主要有四块内容:JVM Misc、JVM Memory Pools(Heap)、JVM Memory Pools(Non-Heap)、Garbage Collection。其中与我们此次较为相关的主要是:JVM Memory Pools(Heap)和 Garbage Collection。
JVM Memory Pools(Heap) 展示 JVM 堆内存的使用情况,主要包括了新生代的 Survivor 区、Eden Space 区、老年代。

Garbage Collection 展示 JVM 的垃圾回收情况,主要包括垃圾回收频率(ops 表示一秒回收几次,一般 0.5 是比较合理的值)、每次 GC 停顿时长(一般 80ms 以下是合理值)、分配到新生代/晋升老年代的内存。

我们要进行 JVM 性能优化,那么最简单的一个方法就是观察 Garbage Collection 的 GC 频率以及停顿时间,我们大致就能判断出应用的内存利用效率。之后根据这两个值的实际情况,将其调整到合理的范围内,提高 JVM 的利用率。
如果一个应用的 GC 频率只有 0.02,即每秒 GC 0.02 次,那么需要 50 秒才 GC 一次,那么其 GC 频率是很低的。这时候很可能是分配了较大的新生代空间,这使得其很久才需要 GC 一次。这时候我们再看看其停顿时间,如果停顿时间也很短的话,那我们就可以判定该应用的内存有优化的空间。
文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。
在这种情况下,一般都是缩小分配的新生代的空间。新生代空间一旦变小了,那么其分配完的时间就会缩减。一旦空间被分配完,那么就会启动进行 GC 操作。我们就是通过调整 JVM 的内存空间,来提高 GC 的频率,从而使其处于一个合理的空间。
在进行内存空间调整的时候,为了避免内存剧烈波动导致的问题,一般我们都是小步快跑地一点点调整。先调整一点试一试,没太大问题之后再调整到目标值。 毕竟是生产环境,要是出了什么叉子,那就得提桶跑路了,还是谨慎为好!
看到这里,想必大家应该也知道怎么做了。接下来无非就是调整 JVM 内存空间的三个参数(-Xmx -Xms -Xmn),使 GC 频率与 GC 停顿时间处于合理的区间。
应用层面优化
除了 GC 频率、GC 停顿时间,我们还能从应用的类型来分析 JVM 的内存消耗情况。
例如对于接口类型的系统来说,很多请求都是 1 秒中之内就结束。对于这种类型的请求,他们进入应用时会分配内存,结束时内存就会立刻被回收,留存下来的对象很少。这种应用的 JVM 内存情况大概是这样的:新生代消耗比较大,并且随着周期性回收内存,但老年代的内存消耗则更小。对于那些持续性处理的应用,例如持续时间长的应用处理。因为其存活时间较久,所以可能会有更多的对象晋升到老年代,因此老年代的内存消耗就比较大。
通过观察 JVM 年轻代与老年代的内存消耗情况,再结合应用本身的特性,我们可以发现应用中不合理的地方,再对应用进行针对性的优化。例如:应用某个地方每次都会存储大量的临时数据到内容中,这样就造成了 JVM 可能爆发 GC,从而导致应用卡顿。
总结
总结一下本篇文章的调优方法:通过观察 GC 频率和停顿时间,来进行 JVM 内存空间调整,使其达到最合理的状态。调整过程记得小步快跑,避免内存剧烈波动影响线上服务。 这其实是最为简单的一种 JVM 性能调优方式了,可以算是粗调吧。但 JVM 性能调优还有更多、更详细的参数,后续有机会我们再聊聊。
此外,通过观察 JVM 年轻代与老年代的情况,也可以帮助我们对应用进行针对性的优化,从而提升应用本身的性能。
如果你之前没了解过 JVM 的基础理论知识,那么你可能看不懂这篇文章。那么我推荐你看看我的「JVM 基础入门系列」,文章由浅入深、循序渐进,可以让你对 JVM 有个感性的理解。看完之后再来看这篇文章,你肯定有种豁然开朗的感觉!
JVM 基础入门系列传送门:JVM 基础入门系列 - 陈树义的博客
关于 JVM 性能调优,就分享到这里吧。
谢谢大家的阅读。如果文章对你有帮助,点个 「在看」 ,或者分享到朋友圈。
文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。
听说 JVM 性能优化很难?今天我小试了一把!的更多相关文章
- JVM性能优化, Part 3 垃圾回收
ImportNew注:本文是JVM性能优化 系列-第3篇-<JVM性能优化, Part 3 —— 垃圾回收> 第一篇 <JVM性能优化, Part 1 ―― JVM简介 > 第 ...
- JVM性能优化, Part 1 ―― JVM简介
JVM性能优化这些列文章共分为5章,是ImportNew上面翻译自Javaworld: 第1章:JVM技术概览 第2章:编译器 第3章:垃圾回收 第4章:并发垃圾回收 第5章:可伸缩性 众所周知,Ja ...
- JVM性能优化系列-(1) Java内存区域
1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 ...
- JVM性能优化系列-(2) 垃圾收集器与内存分配策略
2. 垃圾收集器与内存分配策略 垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如 ...
- JVM 性能优化, Part 4: C4 垃圾回收
ImportNew注:本文是JVM性能优化 系列-第4篇.前3篇文章请参考文章结尾处的JVM优化系列文章.作为Eva Andreasson的JVM性能优化系列的第4篇,本文将对C4垃圾回收器进行介绍. ...
- JVM性能优化, Part 2 ―― 编译器
作为JVM性能优化系列文章的第2篇,本文将着重介绍Java编译器,此外还将对JIT编译器常用的一些优化措施进行讨论(参见“JVM性能优化,Part 1″中对JVM的介绍).Eva Andreasson ...
- 一文学会JVM性能优化
实战性能优化 1 重新认知JVM 之前我们画过一张图,是从Class文件到类装载器,再到运行时数据区的过程,现在咱们把这张图不妨丰富完善一下,展示了JVM的大体物理结构图. 执行引擎:用于执行JVM字 ...
- JVM性能优化简介
01. JVM是什么 概述: 大白话: 全称Java Virtual Machine(Java虚拟机), 它是一个虚构出来的计算机, 通过实际的计算机来模拟 ...
- JVM性能优化系列-(4) 编写高效Java程序
4. 编写高效Java程序 4.1 面向对象 构造器参数太多怎么办? 正常情况下,如果构造器参数过多,可能会考虑重写多个不同参数的构造函数,如下面的例子所示: public class FoodNor ...
随机推荐
- Insertion Sort and Merge Sort
Insertion Sort(插入排序) 思路:for 循环遍历数组中的每一个数 用while将每次遍历到的数于左侧的数进行对比,将小的排到左边 void InsertionSort(int*A, i ...
- xlrd、xlwt 库
1. 安装与介绍 2. xlrd 3. xlwt 1. 安装与介绍 xlrd 模块实现对excel文件内容读取,xlwt 模块实现对excel文件的写入. 模块安装: pip install xlrd ...
- D - The Frog's Games (二分)
The annual Games in frogs' kingdom started again. The most famous game is the Ironfrog Triathlon. On ...
- B - 抽屉 POJ - 2356 (容斥原理)
The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers ...
- 01- APP移动端测试怎么测试?APP测试方法大全。
由于智能手机时代来临,很多产品都有了APP,作为一个测试人员掌握APP测试是必要的. 在展开APP测试之前,首先了解一下几个点: 1.基于软件测试框架之上.复习下软件测试框架. 2.框架的内容贯穿于A ...
- 微信小程序中的自定义组件
微信小程序中的组件 前言 之前做小程序开发的时候,对于开发来说比较头疼的莫过于自定义组件了,当时官方对这方面的文档也只是寥寥几句,一笔带过而已,所以写起来真的是非常非常痛苦!! 好在微信小程序的库从 ...
- DVWA之DOM XSS(DOM型跨站脚本攻击)
目录 Low Medium High Impossible Low 源代码: <?php # No protections, anything goes ?> 从源代码可以看出,这里low ...
- 截取字符串长度,超出部分用省略号代替 PHP
function subText($text, $length){ if (mb_strlen($text, 'utf8') > $length) { return mb_substr($tex ...
- java+selenium使用JS、键盘滑动滚动条
本篇文章介绍如何使用JS和键盘对象对页面进行滑动滚动条-------------主要针对java做自动化测试的同学 一:使用键盘对象操作滚动条 //导包 import org.openqa.selen ...
- nginx日志文件按天记录定时清理循环记录
问题 nginx日志默认记录在一个文件access.log中,时间长了会导致日志文件特别大,甚至磁盘占满. 解决方案 使用以下方法,将access.log文件每天一个,然后清过15天以前的文件. 方法 ...