Java 性能优化系列之3.2[JVM调优]
发布日期:2021-07-01 05:42:53 浏览次数:2 分类:技术文章

本文共 4621 字,大约阅读时间需要 15 分钟。

实用JVM参数

1. JIT 编译参数

JIT(Just-In-Time)编译器, 可以在运行时将字节码编译成本地代码,从而提升函数的执行效率。

-XX:CompileThreshold为 JIT编译的阈值, 当函数的调用次数超过-XX:CompileThreshold时,JIT就将字节码编译成本地机器码。

在Client 模式下, XX:CompileThreshold 的取值为1500;

在Server 模式下, 取值是 10000.

JIT编译完成后, JVM便会使用本地代码代替原来的字节码解释执行。

为了内合理的设置JIT编译的阈值, 可以使用-XX:_CITime打印出JIT编译的耗时, 也可以使用-XX:+PrintCompilation 打印出JIT编译的信息。

看例子:

package com.oscar999.performance.JVMTune;public class TestJIT {	static long i = 0;	/**	 * @param args	 */		public static void testJIT(){		i++;	}	public static void main(String[] args) {		// TODO Auto-generated method stub		for(int j=0;j<1488;j++)			testJIT();		long end = System.currentTimeMillis();	}}
使用命令运行:

java -XX:CompileThreshold=1500 -XX:+PrintCompilation -XX:+CITime com.oscar999.performance.JVMTune.TestJIT

将以上循环次数从1488 换成 1588, 再运行

可以看到, 大于 1500时, 做了编译成本地码的动作。

2. 堆快照(堆Dump)

获得程序的堆快照文件有很多方法, 比较常用的取得堆快照文件的方法是使用-XX:+HeapDumpOnOutOfMemoryError 参数在程序发生OOM时,导出应用程序的当前堆快照。

-Xmx10m -XX:+HeapDumpOnOutOfMemoryError -XX:heapDumpPath=C:\m.hprof

3. 错误处理

当系统发生OOM错误时,虚拟机在错误发生时运行一段第三方脚本, 比如, 当OOM发生时,重置系统

-XX:OnOutOfMemoryError=c:\reset.bat

4. 获取GC信息

JVM虚拟机也提供了许多参数帮助开发人员获取GC信息。

可以使用  -verbose:gc 或者 -XX:+PrintGC.

如果要获得更加详细的信息, 可以使用 -XX:+PrintGCDetails.

如果需要查看新生对象晋升老年代的实际阈值, 可以使用参数 -XX:+PrintTenuringDistribution

如果需要查看GC与实际程序相互执行的耗时, 可以使用 -XX:+PrintGCApplicationt-StoppedTime 和 -XX:+PrintGCApplicationConcurrentTime参数。

可以使用 -Xloggc 参数指定GC日志的输出位置。 如 -Xloggc:C:\gc.log

5. 类和对象跟踪

-XX:+TraceClassLoading 参数用于跟踪类加载情况

-XX:+TraceClassUnloading 用于跟踪类卸载情况。

除了类的跟踪, JVM 还提供了 -XX:+PrintClassHistogram 开关用于打印运行时实例的信息。 当此开关被打开时,  当Ctrl+Break 被按下, 会输出系统内类的统计信息。

6. 控制GC

-XX:+DisableExplicitGC 选项用于禁止显式的GC操作, 即禁止在程序中使用System.gc() 触发Full GC.

-Xnoclassgc 参数, 不回收类, 进而提升GC的性能。

-Xincgc, 一旦启用这个参数,系统便会进行增量式的 GC. 增量式的GC使用特定算法让GC线程和应用程序线程交叉执行,从而减小应用程序因GC而产生的停顿时间。

7. 选择类校验器

在JDK1.6中默认开启新的类校验器,加速类的记载, 可以使用 -XX:-UseSplitVerifier参数指定使用旧的类校验器。

如果新的校验器校验失败,可以使用老的校验器再次校验。可以使用开关 -XX:-FailOverToOldVerifier关闭再次校验的功能

8. Solaris 下线程控制

在 Solaris 下, JVM提供了几个用于线程控制的开关

-XX:+UseBoundTreads: 绑定所有用户线程到内核线程, 减少线程进入饥饿状态的次数

-XX:+UserLWPSynchronization: 使用内核线程替换线程同步

-XX:+UserVMInterruptibleIO: 运行运行时中断线程。

9.. 使用大页

对同样大小的内存空间, 使用大页后, 内存分页的表现就会减少, 从而可以提升CPU从虚拟内存地址映射到物理内存地址的能力。 在支持大页的操作系统中,使用JVM参数让虚拟机使用大页,从而提升系统性能。

-XX:+UserlargePages: 启用大页

-XX:LargePageSizeInBytes: 指定大页的大小

10. 压缩指针

在64位虚拟机上, 应用程序所占内存的大小要远远超出其32位版本(约1.5 倍左右)。这是因为64位系统拥有更宽的寻址空间, 与32位系统相比,指针对象的长度进行了翻倍。为了解决这个问题,

 64位的JVM虚拟机可以使用 -XX:+UseCompressedOops参数打开指针压缩,从一定程度上减少内存的消耗,可以对以下指针进行压缩:

Class的属性指针

对象的属性指针

普通对象数组的每个元素指针

实战JVM调优

Tomcat 启动加速

使用 startup.bat 启动Tomcat 服务器时, start.bat  调用了bin 目录下的calalina.bat 文件。

设置环境变量CATALINA_OPTS 或者JAVA_OPTS都可以设置tomcat  的JVM优化参数。

set CATALINA_OPTS=-Xloggc:gc.log -XX:+PrintGCDetails

为了减少Minor GC的次数, 增大新生代

set CATALINA_OPTS=%CATALINA_OPTS% -Xmx32M -Xms32M

禁用显示GC

set CATALINA_OPTS=%CATALINA_OPTS% -XX:+DisableExplicitGC

在堆内存不变的前提下,为了能进一步减少Minor GC的次数,可以扩大新生代的大小

set CATALINA_OPTS=%CATALINA_OPTS% -XX:NewRation=2

为了加快Minor GC的速度,在多核计算机上可以考虑使用新生代并行回收收集器,加快Minor GC 的速度

set CATALINA_OPTS=%CATALINA_OPTS% -XX:+UseParallelGC

由于JVM虚拟机在加载类时,处于完全考虑,会对Class进行校验和认证,如果类文件是可信任的, 为了加快程序的运行速度,也可以考虑禁用这些效应:

set CATALINA_OPTS=%CATALINA_OPTS% -Xverify:none

JMeter介绍和使用

JMeter是Apache 下基于Java 的一款性能测试和压力测试工具。它基于Java 开发,可对HTTP 服务器和FTP服务器,甚至是数据库进行压力测试。

线程组将模拟用户线程访问Tomcat 服务器。

在线程组之下,需要给线程组分配相应的采样器, 比如HTTP请求, FTP请求,数据库连接等。

除线程组和采样器外,最后还需要一份测试报告。JMeter可以给出各种形式或侧重于各个方面的测试报告。

调优前:

从以上图中可以看到, 最大堆为 256MB, 但在实际使用中, 只使用了50MB.因此, 引起了频繁的GC.

在永久区,最大为64MB,而实际使用时,初始值约在10MB左右,并经历一次扩容,达到19MB左右,基本稳定在19MB.

调优过程

为了减少GC次数, 可以使用合理的堆大小和永久区大小。这里将堆大小设置为512MB, 永久区使用32MB, 同时, 禁用显示GC, 并去掉类校验。参数如下:

set CATALINA_OPTS=%CATALINA_OPTS% "-Xmx512M"set CATALINA_OPTS=%CATALINA_OPTS% "-Xms512M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:PermSize=32M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:MaxPermSize=32M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:+DisableExplicitGC"set CATALINA_OPTS=%CATALINA_OPTS% "-Xverify:none"
为了进一步提高系统的吞吐量, 可以尝试使用并行回收收集器代替串行收集器。

set CATALINA_OPTS=%CATALINA_OPTS% "-Xmx512M"set CATALINA_OPTS=%CATALINA_OPTS% "-Xms512M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:PermSize=32M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:MaxPermSize=32M"set CATALINA_OPTS=%CATALINA_OPTS% "-XX:+DisableExplicitGC"set CATALINA_OPTS=%CATALINA_OPTS% "-Xverify:none"set CATALINA_OPTS=%CATALINA_OPTS% -XX:+UseParallelGCset CATALINA_OPTS=%CATALINA_OPTS% -XX:+UseParallelOldGCset CATALINA_OPTS=%CATALINA_OPTS% -XX:ParallelGCThreads=8
总结一下: JVM调优的主要过程有:

确定堆内存大小(-Xmx, -Xms)

合理分配新生代和老生代(-XX:NewRation, -Xmn, -XX:SurvivorRatio)

确定永久区大小: -XX:Permsize, -XX:MaxPermSize

选择垃圾收集器

对垃圾收集器进行合理的设置

除此之外,禁用显示GC(-XX:+DisableExplicitGC), 禁用类元数据回收(-Xnoclassgc), 禁用类验证(-Xverfy:none)等设置, 对提升系统性能也有一定的帮助。

转载地址:https://oscar.blog.csdn.net/article/details/47271531 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring+Hibernate 零散知识点
下一篇:Java 性能优化系列之4[Java性能调优工具]

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月11日 13时48分52秒