“java -server”和“java -client”之间的真正区别?

“java -server”和“java -client”之间有没有实际的区别? 我只能在Sun的网站上find一个模糊的“服务器启动较慢但运行速度更快”。 真正的区别是什么? (目前使用JDK 1.6.0_07)

这实际上与HotSpot和默认选项值 ( Java HotSpot VM选项 )相关联,这些选项在客户端和服务器configuration之间有所不同。

从白皮书( The Java HotSpot Performance Engine Architecture )的第2章开始 :

JDK包含两种types的VM – 客户端产品和针对服务器应用程序调优的VM。 这两个解决scheme共享Java HotSpot运行时环境代码库,但使用不同的编译器,这些编译器适合于客户端和服务器的独特性能特征。 这些差异包括编译内联策略和堆默认值。

尽pipe服务器和客户端虚拟机类似,但是服务器虚拟机已经过特殊调整,以最大化运行速度。 它旨在执行长时间运行的服务器应用程序,这些应用程序需要最快的运行速度,而不是快速启动时间或更小的运行时内存占用量。

客户端VM编译器可用作旧版本JDK所使用的Classic VM和实时(JIT)编译器的升级。 客户端VM为应用程序和小应用程序提供改进的运行时间性能。 Java HotSpot客户端虚拟机经过特别调整,可以减less应用程序的启动时间和内存占用,使其特别适合于客户端环境。 一般来说,客户端系统对GUI更好。

所以真正的区别也在编译器级别上:

客户端VM编译器不会尝试在服务器虚拟机中执行许多由编译器执行的更复杂的优化,但作为交换,它需要更less的时间来分析和编译一段代码。 这意味着客户端虚拟机可以更快地启动,并且需要更小的内存占用量。

Server VM包含一个高级自适应编译器,支持通过优化C ++编译器执行的许多相同types的优化,以及传统编译器无法完成的一些优化,例如跨虚拟方法调用的积极内联。 与静态编译器相比,这是一个有竞争力的性能优势。 自适应优化技术在其方法中是非常灵活的,并且典型地甚至比先进的静态分析和编译技术更胜一筹。

注: jdk6更新10 (请参阅更新发行说明:1.6.0_10中的更改 )的发布尝试提高启动时间,但是由于与热点选项不同的原因,打包方式与更小的内核不同。


G. Demecki 在评论中指出,在64位版本的JDK中, -client选项被忽略了很多年。
看到Windows的java命令 :

 -client 

selectJava HotSpot客户端VM。
目前支持64位的JDK忽略此选项,而是使用Java Hotspot Server VM

旧版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版本,大部分内存限制和初始分配都要高得多。

但是,这些值可能会改变体系结构,操作系统和jvm版本的不同组合。 jvm的最新版本已经删除了标志并重新移动了服务器和客户端之间的许多区别。

请记住,您可以使用jvisualvm查看正在运行的jvm所有细节。 如果您拥有设置JAVA_OPTS用户或模块​​,或使用更改命令行选项的脚本,则此function非常有用。 这也可以让你实时监控和空间的使用情况以及其他很多的统计数据。

我刚刚注意到的一个区别是,在“客户端”模式下,JVM实际上将一些未使用的内存提供给操作系统 – 而在“服务器”模式下,一旦JVM抓取内存,它就不会给它背部。 这就是它在Solaris上如何使用Java6(使用prstat -Z来查看分配给进程的内存量)。

Oracle的在线文档为Java SE 7提供了一些信息。

在java -用于Windows 的Java应用程序启动程序页面上,在64位JDK中忽略-client选项:

selectJava HotSpot客户端VM。 一个支持64位的jdk目前忽略这个选项,而是使用Java HotSpot Server VM。

然而(为了使事情有趣),在服务器下面说:

selectJava HotSpot Server VM。 在支持64位的jdk上,只支持Java HotSpot Server虚拟机,所以-server选项是隐含的。 这将在未来的版本中发生变化。

“ 服务器级机器检测”页面提供有关按操作系统和体系结构select哪个VM的信息。

我不知道这适用于JDK 6有多less。

-client和-server系统是不同的二进制文件。 它们本质上是两个不同的编译器(JIT),连接到相同的运行时系统。 客户端系统适用于需要快速启动时间或占用空间小的应用程序,服务器系统最适合整体性能最为重要的应用程序。 一般来说,客户端系统更适合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--) { } } } 

注意:代码只被编译一次! 这两个class的class都是一样的!

用-client:
java.exe -client -classpath C:\ mywork \ classes com.blogspot.sdoulger.LoopTest
花费的时间:766

用-server:
java.exe -server -classpath C:\ mywork \ classes com.blogspot.sdoulger.LoopTest
花费的时间:0

看来服务器系统更积极的优化,删除循环,因为它明白,它不会执行任何操作!

参考

IIRC服务器虚拟机在启动时做了更多的热点优化,所以运行速度更快,但需要更长的时间才能启动并使用更多的内存。 客户端VM推迟大部分优化以允许更快的启动。

编辑添加: 这是从Sun 的一些信息 ,这不是很具体,但会给你一些想法。

从Goetz – Java并发实践:

  1. debugging提示:对于服务器应用程序,确保在调用JVM时始终指定-server JVM命令行开关, 即使对于开发和testing也是如此 。 服务器JVM执行比客户端JVM更多的优化,例如将循环中没有修改的variables提取出来; 可能在开发环境(客户端JVM)中工作的代码可能会在部署环境(服务器JVM)中崩溃。 例如,如果我们忘记在清单3.4中声明variablesasleep为volatile, 那么服务器JVM可以将testing从循环中提取出来(将其变成无限循环),但是客户机JVM不会 。 在开发过程中出现的无限循环比仅在生产中出现的成本要低得多。

代码3.4 数羊。

volatile boolean asleep; ... while (!asleep) countSomeSheep();

我的重点。 因人而异

IIRC,它涉及垃圾收集策略。 理论上,客户端和服务器在短期对象方面是不同的,这对于现代的GCalgorithm是重要的。

这是服务器模式的链接 。 唉,他们不提客户端模式。

总的来说, 这是一个非常透彻的 GC的链接 。 这是一个更基础的文章 。 不知道,如果任何地址的服务器VS客户端,但这是相关的材料。

在没有绒毛的事情上,肯·斯佩和格伦·范登堡都在做这样的事情。

我没有注意到2之间的启动时间有任何差异,但是通过“-server”(Solaris服务器,每个使用SunRays来运行应用程序)的应用程序性能都有一个非常小的改进。 那是在1.5以下。

上次我看了一下这个(不可否认的是,有一段时间了),我注意到的最大的区别是垃圾回收。

IIRC:

  • 服务器堆虚拟机具有与客户机虚拟机不同的世代,并且具有不同的垃圾收集algorithm。 这可能不是真的了
  • 服务器虚拟机将分配内存,而不是释放到操作系统
  • 服务器虚拟机将使用更复杂的优化algorithm,因此对优化有更大的时间和内存要求

如果您可以比较两个Java虚拟机,一个客户端,一个使用jvisualvm工具的服务器,则应该看到垃圾收集的频率和效果以及代数的差异。

我有一对截图,显示差异非常好,但我不能重现,因为我有一个64位的JVM,只实现服务器虚拟机。 (而且我也不能打扰在我的系统上下载和争夺32位版本。)

这似乎不是这种情况了,试图在服务器和客户端虚拟机上运行一些代码在Windows上,我似乎得到了同样的代模型…

当从1.4迁移到1.7(“1.7.0_55”)版本时,我们在这里观察到的情况是,在客户端和服务器模式下,默认值分配给hemsize | permsize | ThreadStackSize参数没有这种差异。

顺便说一句,( http://www.oracle.com/technetwork/java/ergo5-140223.html )。 这是从上面链接采取的片段。

 initial heap size of 1/64 of physical memory up to 1Gbyte maximum heap size of ¼ of physical memory up to 1Gbyte 

ThreadStackSize在1.7中更高,在经过Open JDK论坛的时候,在1.7版本中有讨论说帧大小有点高。 据信,根据您的应用程序的行为,可以在运行时测量真正的差异