Jdk17中的服务器热点和客户端热点有什么区别?
JDK17中的问题是关于服务器热点和客户端热点之间的区别。在JDK17中,-client和-server是两个不同的二进制文件。它们实际上是两个不同的编译器(JITs),与同一个运行时系统进行交互。客户端系统适用于需要快速启动时间或小的占用空间的应用程序,而服务器系统适用于整体性能最重要的应用程序。一般来说,客户端系统更适合交互式应用程序,如GUI。
在给定的代码示例中,我们使用两个开关运行以下代码:
package com.blogspot.sdoulger; public class LoopTest { public LoopTest() { super(); } public static void main(String[] args) { long start = System.currentTimeMillis(); spendTime(); long end = System.currentTimeMillis(); System.out.println("Time spent: "+ (end-start)); LoopTest loopTest = new LoopTest(); } private static void spendTime() { for (int i =500000000;i>0;i--) { } } }
注意:该代码只编译一次!在两次运行中,类是相同的!
使用-client选项运行结果为:
java.exe -client -classpath C:\mywork\classes com.blogspot.sdoulger.LoopTest Time spent: 766
使用-server选项运行结果为:
java.exe -server -classpath C:\mywork\classes com.blogspot.sdoulger.LoopTest Time spent: 0
似乎更激进的服务器系统的优化删除了循环,因为它理解到循环没有执行任何操作!根据这个例子,我们可以看到在服务器系统中,循环被优化掉,所以时间花费为0。
因此,区别在于客户端热点和服务器热点对代码的不同优化策略。客户端热点更关注快速启动和小的占用空间,而服务器热点更关注总体性能。
在旧版本的Java中,最直观的区别是分配给-client
和-server
应用程序的内存。例如,在我的Linux系统上,我得到以下结果:
$ java -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version' uintx AdaptivePermSizeWeight = 20 {product} uintx ErgoHeapSizeLimit = 0 {product} uintx InitialHeapSize := 66328448 {product} uintx LargePageHeapSizeThreshold = 134217728 {product} uintx MaxHeapSize := 1063256064 {product} uintx MaxPermSize = 67108864 {pd product} uintx PermSize = 16777216 {pd product} java version "1.6.0_24"
因为默认情况下是-server
,但使用-client
选项时,我得到以下结果:
$ java -client -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version' uintx AdaptivePermSizeWeight = 20 {product} uintx ErgoHeapSizeLimit = 0 {product} uintx InitialHeapSize := 16777216 {product} uintx LargePageHeapSizeThreshold = 134217728 {product} uintx MaxHeapSize := 268435456 {product} uintx MaxPermSize = 67108864 {pd product} uintx PermSize = 12582912 {pd product} java version "1.6.0_24"
因此,对于这个java
版本,使用-server
时,大部分内存限制和初始分配要高得多。
然而,这些值可能因体系结构、操作系统和jvm版本的不同而发生变化。最近的jvm版本已删除了一些标志,并消除了许多服务器和客户端之间的区别。
还要记住,您可以使用jvisualvm
查看运行中的jvm
的所有细节。如果您的用户或模块设置了JAVA_OPTS
或使用了更改命令行选项的脚本,这将非常有用。这还可以让您实时监控堆和永久代的使用情况以及许多其他统计信息。
在CentOS 7上,我在-server
和-client
模式下得到了相同的数字,版本为"1.7.0_79" [Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM]。
这就是我提供答案的原因。这不是关于具体数值,而是为了使任何人在任何时候都能找到他们特定jvm版本的答案。
JDK 17中的服务器和客户端热点之间的区别是由于HotSpot和默认选项值之间的联系。根据白皮书的第二章,“JDK包括两种VM的版本-一种是针对客户端的,另一种是针对服务器应用程序进行调优的VM。这两种解决方案共享Java HotSpot运行时环境代码库,但使用不同的编译器,适用于客户端和服务器的各自独特的性能特征。这些差异包括编译内联策略和堆默认值。虽然服务器和客户端VM相似,但服务器VM经过特别调优以最大化峰值运行速度。它适用于执行长时间运行的服务器应用程序,这些应用程序更需要尽可能快的运行速度,而不是快速启动时间或更小的运行时内存占用。” 客户端VM编译器用于升级经典VM和先前版本JDK使用的即时(JIT)编译器。客户端VM提供了改进的运行时性能,适用于应用程序和小程序。Java HotSpot客户端VM经过特别调优,以减少应用程序启动时间和内存占用,因此非常适合客户端环境。总体而言,客户端系统更适合GUI。因此,真正的区别也存在于编译器层面上。客户端VM编译器不会尝试执行服务器VM中执行的许多更复杂的优化,但作为交换,它需要较少的时间来分析和编译一段代码。这意味着客户端VM可以更快地启动,并且需要较小的内存占用。服务器VM包含一个先进的自适应编译器,支持许多与优化C++编译器执行的相同类型的优化,以及一些传统编译器无法执行的优化,例如跨虚拟方法调用的积极内联。这是与静态编译器相比的竞争性和性能优势。自适应优化技术在方法上非常灵活,并且通常优于高级静态分析和编译技术。需要注意的是,自JDK的64位版本起,多年来已忽略了-client选项。Windows的java命令中指出:“选择Java HotSpot Client VM。64位容量JDK当前忽略此选项,而是使用Java Hotspot Server VM。”在JavaSE6/服务器级别机器检测中,只有在32位Windows系统上才无条件选择-client。其他系统会检查机器是否为“服务器级别”,即至少具有2个核心和至少2GiB的内存。这就解释了为什么几乎所有东西都使用-server。即使是最便宜的电脑,也是“服务器级别”的机器。Sun/Oracle的64位版本甚至不带有客户端JVM。最后,JDK6更新10及更高版本具有后台进程,将运行时库保留在内存中,相比按需全部加载,可以使新进程的启动速度更快。虽然客户端VM也进行了积极内联,但是这个答案应该更新,因为64位JDK版本多年来已经忽略了-client选项。