JVM实用参数(二)JVM类型、工作模式及代码缓存

本文详细介绍了JVM的两种类型——Client和Server模式,分析了它们的区别,特别是编译器优化上的差异。接着探讨了JVM的工作模式,包括解释模式、编译模式和混合模式,并解释了默认的mixed模式的优势。最后,讨论了代码缓存的重要性,包括相关参数调整,以及如何避免代码缓存溢出导致的性能问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、JVM的类型

当虚拟机运行在-client模式的时候,使用的是一个代号为C1的轻量级编译器, 而-server模式启动的虚拟机采用相对重量级,代号为C2的编译器. C2比C1编译器编译的相对彻底,,服务起来之后,性能更高.

-server 模式启动时,速度较慢,但是一旦运行起来后,性能将会有很大的提升。

大意是说,这两个JVM是使用的不同编译器。Client JVM适合需要快速启动和较小内存空间的应用,它适合交互性的应用,比如GUI;而Server JVM则是看重执行效率的应用的最佳选择。不同之处包括:编译策略、默认堆大小、内嵌策略。

很明显,Client VM的编译器没有像Server VM一样执行许多复杂的优化算法,因此,它在分析和编译代码片段的时候更快。而Server VM则包含了一个高级的编译器,该编译器支持许多和在C++编译器上执行的一样的优化,同时还包括许多传统的编译器无法实现的优化。

JVM类型的切换

因此,如果想要在windows平台下从Client JVM切换到Server JVM,需要下载JDK而非JRE。打开JDK安装目录(即%JAVA_HOME%):我们可以看到%JAVA_HOME%\jre\bin下有一个server和client文件夹,这里面各有一个jvm.dll,但是大小不同,这就说明了它们是不同的JVM的文件;

打开 %JAVA_HOME%\jre\lib\i386\jvm.cfg文件

# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
# List of JVMs that can be used as an option to java, javac, etc.
# Order is important -- first in this list is the default JVM.
# NOTE that this both this file and its format are UNSUPPORTED and
# WILL GO AWAY in a future release.
#
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
-client KNOWN
-server KNOWN

再看看下方的配置,第一行就配置了使用client方式,因此首选使用client模式的JVM,这就是为什么一开始的java -version命令会输出Java HotSpot(TM) Client VM的原因了。现在将配置交换一下,再在命令行中输入java -version,则会得到不同的结果:

这就将JVM的工作模式切换到Server了,这个修改是全局的,以后使用到的这个JVM都是工作在Server模式的。

当然,如果你不想全局改动,也可以按照下面在java命令后加上-server或者-client来明确指定本次java命令需要JVM使用何种模式来工作;

二、JVM工作模式

在命令行里输入java -X,你会看到以下结果:

 -Xmixed           混合模式执行 (默认)
 -Xint             仅解释模式执行

其实这两个是JVM工作的模式。JVM有以下几种模式:-Xint, -Xcomp, 和 -Xmixed。从上图的输出结果中也可以看到,mixed是JVM的默认模式,其实在文章一开始的时候就提到了,因为在java -version命令中,输出了以下内容:

Java HotSpot(TM) Client VM (build 25.45-b02, mixed mode)

中间的mixed mode就说明当前JVM是工作在mixed模式下的。-Xint和-Xcomp参数和我们的日常工作不是很相关,但是我非常有兴趣通过它来了解下JVM。

-Xint

代表解释模式(interpreted mode),-Xint标记会强制JVM以解释方式执行所有的字节码,当然这会降低运行速度,通常低10倍或更多。现在通过刚才的例子(没有重新编译过)来验证一下:

可以看到,在都使用Client JVM的前提下,混合模式下,平均耗时150ms,然而在解释模式下,平均耗时超过1600ms,这基本上是10倍以上的差距。

-Xcomp

代表编译模式(compiled mode),与它(-Xint)正好相反,JVM在第一次使用时会把所有的字节码编译成本地代码,从而带来最大程度的优化。这听起来不错,因为这完全绕开了缓慢的解释器。然而,很多应用在使用-Xcomp也会有一些性能损失,但是这比使用-Xint损失的少,原因是-Xcomp没有让JVM启用JIT编译器的全部功能。因此在上图中,我们并没有看到-Xcomp比-Xmixed快多少。

-Xmixed

代表混合模式(mixed mode),前面也提到了,混合模式是JVM的默认工作模式。它会同时使用编译模式和解释模式。对于字节码中多次被调用的部分,JVM会将其编译成本地代码以提高执行效率;而被调用很少(甚至只有一次)的方法在解释模式下会继续执行,从而减少编译和优化成本。JIT编译器在运行时创建方法使用文件,然后一步一步的优化每一个方法,有时候会主动的优化应用的行为。这些优化技术,比如积极的分支预测(optimistic branch prediction),如果不先分析应用就不能有效的使用。这样将频繁调用的部分提取出来,编译成本地代码,也就是在应用中构建某种热点(即HotSpot,这也是HotSpot JVM名字的由来)。使用混合模式可以获得最好的执行效率。

三、代码缓存

-XX:InitialCodeCacheSize
-XX:ReservedCodeCacheSize

JVM一个有趣的,但往往被忽视的内存区域是“代码缓存”,它是用来存储已编译方法生成的本地代码。代码缓存确实很少引起性能问题,但是一旦发生其影响可能是毁灭性的。如果代码缓存被占满,JVM会打印出一条警告消息,并切换到interpreted-only 模式:JIT编译器被停用,字节码将不再会被编译成机器码。因此,应用程序将继续运行,但运行速度会降低一个数量级,直到有人注意到这个问题。就像其他内存区域一样,我们可以自定义代码缓存的大小。相关的参数是-XX:InitialCodeCacheSize 和-XX:ReservedCodeCacheSize,它们的参数和上面介绍的参数一样,都是字节值。

-XX:+UseCodeCacheFlushing

如果代码缓存不断增长,例如,因为热部署引起的内存泄漏,那么提高代码的缓存大小只会延缓其发生溢出。为了避免这种情况的发生,我们可以尝试一个有趣的新参数:当代码缓存被填满时让JVM放弃一些编译代码。通过使用-XX:+UseCodeCacheFlushing 这个参数,我们至少可以避免当代码缓存被填满的时候JVM切换到interpreted-only 模式。不过,我仍建议尽快解决代码缓存问题发生的根本原因,如找出内存泄漏并修复它。


  • 初始化的code cache的大小,默认500KB。这个值应该不小于系统最小内存页的大小。
    -XX:InitialCodeCacheSize=size

  • 设置为了JIT编译代码的最大代码cache大小。这个设置默认是240MB,如果关掉了tiered编译,则大小是48MB。这个设置必须比初始化的-XX:InitialCodeCacheSize=size设置值大。
    -XX:ReservedCodeCacheSize=size

注意:可以通过

getconf PAGESIZE

来查看linux内存页大小,数值单位是字节,默认是4096个字节 也就是4KB(看操作系统)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值