在使用"java -server" 和 "java -client"命令时,是否存在实际可感知的差异?
我在Sun的网站上只找到了含糊的描述:
"-server 启动较慢,但应该更快地运行"。
它们之间的真正区别是什么?(当前使用JDK 1.6.0_07版本。)
在使用"java -server" 和 "java -client"命令时,是否存在实际可感知的差异?
我在Sun的网站上只找到了含糊的描述:
"-server 启动较慢,但应该更快地运行"。
它们之间的真正区别是什么?(当前使用JDK 1.6.0_07版本。)
G. Demecki指出在评论中,在64位JDK版本中,-client
选项已经被忽略了多年。
请参见Windows java
命令:
-client
2022年:Holger在评论中提到了JavaSE6 / 服务器级机器检测,并补充道:
仅在32位Windows系统上,
-client
被无条件选择。
其他系统会检查机器是否为“服务器级”,当至少有2个内核和至少2GiB的内存时才能满足。这就解释了为什么几乎所有东西现在都使用
-server
。即使是你能找到的最便宜的电脑,也是“服务器级”机器。Sun/Oracle的64位版本甚至没有提供客户端JVM。
-client
选项已经被忽略了很多年。 - G. Demecki在旧版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"
使用 -server
标志的话,这个 Java
版本的大多数内存限制和初始分配都会更高。
然而,不同的体系结构、操作系统和 jvm 版本的组合可能会导致这些值发生变化。最近的 jvm 版本已经删除了一些标志,并消除了许多 server 和 client 之间的差异。
还要记住,可以通过使用 jvisualvm
来查看运行中的 jvm
的所有详细信息。如果您有设置 JAVA_OPTS
或使用更改命令行选项的脚本的用户或模块,则这将很有用。这也可以让您实时监视堆和 permgen 空间的使用以及许多其他统计信息。
-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
花费时间: 766
使用 -server:
java.exe -server -classpath C:\mywork\classes com.blogspot.sdoulger.LoopTest
花费时间: 0
似乎服务器系统更积极的优化,将循环删除,因为它理解该循环不执行任何操作!
我刚刚注意到的一个区别是,在“客户端”模式下,JVM似乎会将一些未使用的内存返还给操作系统,而在“服务器”模式下,一旦JVM获取了内存,就不会将其归还。至少在Solaris上使用Java6时是这样的(使用prstat -Z
查看进程分配的内存量)。
Oracle的在线文档提供了一些关于Java SE 7的信息。
在Windows系统上的java - Java应用程序启动器页面中,64位JDK将忽略-client
选项:
选择Java HotSpot Client VM。64位JDK当前会忽略此选项并使用Java HotSpot Server VM。
然而(为了使事情变得有趣),在-server
选项下,它表示:
选择Java HotSpot Server VM。对于支持64位的JDK只支持Java HotSpot Server VM因此-server选项是隐式的。这在未来版本中可能会更改。
服务器级别机器检测页面提供了有关操作系统和架构所选虚拟机的信息。
我不知道其中多少适用于JDK 6。
来自Goetz - Java并发实践:
- 调试技巧:对于服务器应用程序,在调用JVM时一定要始终指定
-server
JVM命令行开关,即使是在开发和测试阶段也要这样做。服务器JVM执行了比客户端JVM更多的优化,例如将未在循环中修改的变量提升出循环; 在开发环境(客户端JVM)工作正常的代码在部署环境(服务器JVM)可能会出问题。例如,在第3.4节的示例中,如果我们“忘记”在asleep变量中声明volatile,则服务器JVM可以将测试提升出循环(将其转换为无限循环),但客户端JVM不会。在开发中出现的无限循环比仅在生产中出现的无限循环成本要低得多。
清单3.4。数羊。
volatile boolean asleep;
...
while (!asleep)
countSomeSheep();
我的强调。你的经验可能有所不同。
据我所知,服务器虚拟机在启动时进行更多的热点优化,因此运行速度更快,但启动时间稍长且使用的内存更多。客户端虚拟机将大部分优化推迟以实现更快的启动。
编辑添加:这里是来自Sun的一些信息,它并不是非常具体,但会给您一些想法。
我没有注意到启动时间上的任何差异,但是在应用程序性能方面使用"-server"(Solaris服务器,每个人都使用SunRays运行应用程序)有一些微小的改进。这是在1.5版本下测试的。