基础概念回顾
JDK、JRE、JVM的关系(JDK>JRE>JVM)
JDK = JRE + 开发工具 、JRE = JVM + 类库,具体关系如下图:
JDK(Java Development Kit) 用于开发 Java 应用程序的软件开发工具集合,包括 了 【Java 运行时的环境(JRE)】、【DevelopmentTools开发工具包:解释器(Java):编译器(javac)、Java 归档 (jar)、文档生成器(Javadoc)等工具】。简单的说我们要开发Java程序,就需要安 装某个版本的JDK工具包。
JRE(Java Runtime Enviroment )提供 Java 应用程序执行时所需的环境,由 Java 虚拟机(JVM)、核心类、支持文件等组成。简单的说,我们要是想在某个机器上运 行Java程序,可以安装JDK,也可以只安装JRE,后者体积比较小。
JVM(Java Virtual Machine)(Java 虚拟机)有三层含义,分别是:
-
JVM规范要求
-
满足 JVM 规范要求的一种具体实现(一种计算机程序)
-
一个 JVM 运行实例,在命令提示符下编写 Java 命令以运行 Java 类时,都会创建一 个 JVM 实例,我们下面如果只记到JVM则指的是这个含义;如果我们带上了某种JVM 的名称,比如说是Zing JVM,则表示上面第二种含义
三者在开发运行Java程序时的交互关系:
简单的说,就是通过JDK开发工具,编译以后,可以打包分发给其他装有JRE的机器上去运行。而这个运行的程序,就是通过java命令启动的一个JVM实例,我们所有代码逻辑的执行都运行在这 个JVM实例上 。
关于
Java运行时 和 JVM虚拟机
概念:简单的说JRE就是Java的 “运行时”,包括虚拟机和相关的库等资源。 可以说运行时提供了程序运行的基本环境,JVM在启动时需要加载所有运行时的核心库(Libraries)等资源,然后再加载我们的应用程序字节码,才能让应用程序字节码运行在JVM这 个容器里。
下图为JDK中的开发 [Development Tools工具包] 编译成Class文件到运行时 [JRE-JVM] 的过程:
三大类型事件
-
MinorGC: 收集年轻代内存的GC事件称为 Minor GC
-
MajorGC: 清理老年代空间(Old Space)的GC事件
-
FullGC: 清理整个堆内存空间的GC事件,包括年轻代空间和老年代空间
其实 Major GC 和 Full GC 有时候并不能很好地区分。更复杂的情况是, 很多 Major GC 是由Minor GC 触发的,所以很多情况下这两者是不可分离的。 另外,像G1这种垃圾收集算法,是每次找一小部分区域来进行清理,这部分区域中可能有一部分是年轻 代,另一部分区域属于老年代。
所以我们不要太纠结具体是叫 Major GC 呢还是叫 Full GC ,它们一般都会造成单次较长时间的STW暂停。我们需要关注的是:
某次GC事件,是暂停了所有线程、进而对系统造成了性能影响呢,还是与其他业务线程并发执行、暂停时间几乎可以忽略不计
,比如GC频率高如果暂停时间低的话就会降低延迟,但是牺牲了吞吐率,而如果频率低,暂停时间如果高的话则会提升吞吐率,但会可能提升延迟,而这些就是需要权衡优化的点之一。
关键指标参考
计算机中三个关键指标
-
cpu:因单位时间有限,所以由于业务逻辑不合理而出现瓶颈等...
-
内存:数据可直接使用的暂存空间,GC会回收垃圾,但是GC配置不合理也有可能造成OOM
-
IO(存储+网络):存储数据时持久化的IO过程,分布式多机部署时网络的IO过程。
性能优化常见套路
遵循2/8原则: 所有慢因素按照对性能影响列一个清单,前20%的瓶颈问题对性能影响站80%,也就是说解决这20%性能就会好一大半。
ps:与JVM有关的核心资源cpu和内存。
衡量系统的三个维度 —— [ 延迟(单位: RP)、吞吐量(单位: TPS、QPS)、系统容量 (计算机常用单位)]
-
延迟: 衡量单位 —— RT(Response Time)响应时间,一般为平均响应时间,比如要保障95%用户在可接受响应范围,则可叫做P95(percent95)-95线,而同理99%用户就是99线。那么要保障P95用户平均1s的RT就是保障95%用户请求的平均响应时间为1s。
-
吞吐量: 衡量单位——TPS(TransactionPerSecend)每秒处理的事务(增删改查)数、QPS(QueryPerSecend)每秒处理的请求(查)数。
-
系统容量: 也叫做设计容量,可理解为硬件配置。
此外还可从另外一个维度来讲性能指标分为两类:
业务需求指标: 如吞吐量(QPS、TPS)、响应时间(RT)、并发数、业务成功率等
资源约束指标: 如CPU、内存、I/O等资源的消耗情况。
PS:另外不同种类的系统,关注的性能侧重点还不一样。比如【批处理/流处理型系统】更关注的是吞吐量,延迟可适当放宽。而【高可用的Web型系统】则及关注高并发下的系统响应时间也关注吞吐量。
例: "配置2核4GB的节点,每秒响应200个请求,95%线是20ms,最大响应时间40ms。"
从上文可以解读出基本的性能信息: 响应时间(RT<40ms), 吞吐量(200TPS), 系统配置信息(2C4G)。隐含的条件可能是 "并发请求数不超过200 "。
类似这样的情况,我们可采用的分析优化的手段和方式包括:
使用JDWP(Java Platform Debugger Architecture) 或开发工具做本地/远程调试
系统和JVM的状态监控,收集分析指标
性能分析: CPU使用情况/内存分配分析
常用配置清单
以下为常用配置参数介绍,有点要先说明 —— 大部分情况下,配置GC参数并不是越多越好。原则上只配置最重要的几个参数即可,其他的都保持默认值,除非你对系统的业务特征有了深入的分析和了解,才需要进行某些细微参数的调整。 毕竟,古语有云:“过早优化是万恶之源”。
一、内存参数:
-
-Xmx: 最大堆内存大小
-
-Xms: 初始化时的堆内存大小
-
-Xmn: 等价于-XX:NewSize,指新生代大小(注意:使用 G1 垃圾收集器 不应该 设置该选项,在其他的某些业务场景下可以设置。官方建议设置为
-Xmx
的1/2 ~ 1/4
。) -
-XX:MetaspaceSize: 指定元数据区最小大小(Java8以后)
-
-XX:MaxMetaspaceSize: 指定元数据区最大大小(Java8以后)(注意:Java8 默认不限制 Meta 空间, 一般不允许设置该选项)
-
-XX:PermSize、-XX:MaxPermSize: 分别设置永久代最小大小与最大大小(Java8以前)
-
-XX:MaxDirectMemorySize: 最大直接内存(也就是堆外内存),这个参数跟
-Dsun.nio.MaxDirectMemorySize
效果相同。 -
-XX:MaxTenuringThreshold: 设置转入老年代的存活次数(也就是在新生代未被回收的次数)。如果是0,则直接跳过新生代进入老年代
-
-XX:SurvivorRatio: 新生代中Eden区与两个Survivor区的比值。
-
-XX:NewRatio: 设置新生代和老年代的比值。
-
Xss:设置每个线程栈的字节数。 例如
-Xss1m
指定线程栈为 1MB,与-XX:ThreadStackSize=1m
等价
二、垃圾回收器参数:
-
-XX:+UseG1GC:使用 G1 垃圾回收器(注意:使用 G1垃圾收集器: -XX:+UseG1GC 。原则上不能指定G1垃圾收集器的年轻代大小,否则不仅是画 蛇添足,更是自废武功了。因为G1的回收方式是小批量划定区块(region)进行,可能一次普通GC中 既有年轻代又有老年代,可能某个区块一会是老年代,一会又变成年轻代了。 )
-
-XX:+UseSerialGC:使用串行收集器
-
-XX:+UseParallelGC:使用并行收集器
-
-XX:+UseParalledlOldGC:使用并行老年代收集器
-
-XX:+UseConcMarkSweepGC:使用并发收集器
三、垃圾回收器参数:
-
-XX:+PrintGCDetails: 打印GC日志详情
-
-Xloggc:gc.demo.log : 将日志信息作为文件保存(默认在项目的根目录下,若需指定位置可在前面加路径,如
-Xloggc:/var/log/gc.demo.log)
-
-XX:+PrintGCDateStamps:打印GC时间发生的日期和时间
-
-XX:+PrintGCApplicationStoppedTime: 输出每次GC的持续时间和程序暂停时间;
四、其他参数(诊断or预警):
-
-XX:+-HeapDumpOnOutOfMemoryError: 当
OutOfMemoryError
产生 —— 即内存溢出(堆内存或持久代)时,自动 Dump 堆内存。 因为在运行时并没有什么开销, 所以==在生产机器上是可以使用的==。 示例用法:java -XX:+HeapDumpOnOutOfMemoryError -Xmx256m ConsumeHeap
-
-XX:HeapDumpPath : 与
HeapDumpOnOutOfMemoryError
搭配使用, 指定内存溢出时 Dump 文件的目录。 如果没有指定则默认为启动 Java 程序的工作目录。 示例用法:java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/ ConsumeHeap
自动 Dump 的 hprof 文件会存储到/usr/local/
目录下。 -
-XX:OnError : 发生致命错误时(fatal error)执行的脚本。 例如, 写一个脚本来记录出错时间, 执行一些命令, 或者 curl 一下某个在线报警的url. 示例用法:
java -XX:OnError="gdb - %p" MyApp
可以发现有一个%p
的格式化字符串,表示进程 PID。 -
-XX:OnOutOfMemoryError : 抛出 OutOfMemoryError 错误时执行的脚本。
-
-XX:ErrorFile=filename 选项: 致命错误的日志文件名,绝对路径或者相对路径。
注: 以上只把JVM一些常用配置参数列举出来了,如果要了解完整的JVM配置参数清单,可在官网查看:
Java HotSpot VM Options