Java 基本功06-JVM-性能调优浅谈

304 阅读5分钟

JVM 性能调优浅谈

1. 写给爱学习的小伙伴们

由于 JVM 调优之坑巨大同时为了不误人子弟,我也就在网上查阅资料简单总结了下相关知识,如果有感兴趣的同学可以参考本文和之前的文章来自行学习。
(请参考之前的总结来了解学习,因为我都快忘记了!)

2. JVM 调优概述

2.1 性能定义

1、吞吐量:
	指不考虑 GC 引起的停顿时间和内存消耗,垃圾收集器能支撑应用达到的最高性能指标。

2、延迟:
	延迟的度量标准是缩短由于垃圾收集器引起的时间停顿或者完全消除因为垃圾收集所引起的停顿,避免应用运行时发生抖动。
	
3、内存占用:
	垃圾收集器流畅运行所需要的内存数量。

2.2 调优原则

GC 优化的两个目标:
	1、将进入老年代的对象数量降到最低。
	2、减少 Full GC 的执行时间。
	
GC 优化的基本原则是:
	将不同的 GC 参数应用到两个及以上的服务器上然后比较他们的性能,之后将那些被证明可以提高性能或减少 GC 执行时间的参数应用于最终的工作服务器上。
2.2.1 将进入老年代的对象数量降到最低
除了可以在 JDK 1.7 及更高版本中使用的 G1 收集器以外,其他分代 GC 都是由 Oracle JVM 提供的。关于分代 GC,就是说对象在 Eden 区被创建,然后被转移到 Survivor 区,在此之后剩余的对象会被转入到老年代。也有一些对象由于占用内存过大,在 Eden 区被创建后会直接后被传入老年代。老年代 GC 相对来说会比新生代 GC 更耗时,因此减少进入老年代的对象数量可以显著降低 Full GC 的频率。我们可能会以为减少进入老年代的对象数量意味着把他们留在新生代,事实上正好相反,在新生代内存的大小是可以调节的。
2.2.2 降低 Full GC 的时间
Full GC 的执行时间比 Minor GC 要长很多,因此如果在 Full GC 上花费的时间过多(超过 1s),就很可能会出现超时错误。

	a.如果通过减小老年代内存来减少 Full GC 时间,可能会引起 OutOfMemoryError 或者导致 Full GC 的频率升高。
	
	b.如果通过增加老年代内存来降低 Full GC 的频率,Full GC 的时间可能因此增加。
	
因此,我们需要把老年代的大小设置成一个"合适"的值。

下面是 GC 优化需要考虑的 JVM 参数。
类型 参数 描述
堆内存大小 -Xms 启动 JVM 时堆内存的大小
-Xmx 堆内存最大限制
新生代空间大小 -XX:NewRatio 新生代和老年代的内存比
-XX:NewSize 新生代内大小
-XX:SurvivorRatio Eden 区和 Survivor 区的内存比
GC 优化时最常用的参数是 -Xms,-Xmx 和 -XX:NewRatio。

-Xms 和 -Xmx 参数通常是必须的,所以 NewRatio 的值将对 GC 性能产生重要的影响。

有些人可能会问如何设置永久代内存大小,我们可以用 -XX:PermSize 和 -XX:MaxPermSize 参数来进行设置,但是我们要记住,只有当出现 OutOfMemoryError 错误时我们才需要去设置永久代内存。

2.3 GC 优化的过程

GC 的优化过程和大多数我们常见的提升性能的过程相似,下面是查阅资料整理的流程。
2.3.1 监控 GC 的状态
我们需要监控 GC 从而检查系统中运行的 GC 各种状态。
2.3.2 分析监控结果后来决定是否需要优化 GC
在检查 GC 状态后,我们需要分析监控结构并决定是否需要进行 GC 优化。如果分析结果显示运行 GC 的时间只有 0.1 ~ 0.3 秒,那么就不需要把时间浪费在 GC 优化上,但如果运行 GC 的时间达到 1 ~ 3 秒,甚至大于 10 秒,那么 GC 优化就是很有必要的。

但是我们如果已经分配了大约 10GB 内存给 Java,并且这些内存都是无法省下的,那么久无法进行 GC 优化了。在进行 GC 优化之前,我们需要考虑为什么分配那么大的内存空间,如果我们分配了 1GB 或者 2GB 大小的内存空间并且出现了 OutOfMemoryError,那我们就应该执行 **堆快照(heap dump)**来消除导致异常的原因。

注意:
	a.**堆快照(heap dump)**是一个用来检查 Java 内存中的对象和数据的内存文件。该文件可以通过执行 JDK 中的 jmap 命令来创建。在创建文件的过程中,所有 Java 程序都将暂停,因此,不要在系统执行过程中创建该文件。
	
	大家可以从网上搜索关于 heap dump 的详细说明,这里就不细说了。
2.3.3 设置 GC 类型/内存大小
如果我们决定要进行 GC 优化,那么我们需要选择一个 GC 类型并且为它设置内存大小。此时如果我们有多个服务器,那么就如上文提到的那样,在每台机器上设置不同的 GC 参数并分析他们的区别。
2.3.4 分析结果
在设置完 GC 参数后就可以开始收集数据,请在收集至少 24 小时候在进行结果分析。如果我们足够幸运,我们可能会找到系统的最佳 GC 参数。如若不然,我们还需要分析输出日志并检查分配的内存,然后需要通过不断的调整 GC 类型/内存大小来找到系统最佳的参数。
2.3.5 结束 GC 优化
如果 GC 优化的结果令人满意,就可以将参数应用到所有的服务器上,并且停止 GC 优化。