“java -server”和“java -client”之间有什么实际的区别吗?

我在孙的网站上只能找到一个模糊的

-服务器启动较慢,但应该运行得更快。

真正的区别是什么?(目前使用JDK 1.6.0_07。)


我没有注意到两者在启动时间上有任何不同,但使用“-server”(Solaris服务器,每个人都使用SunRays来运行应用程序)时,应用程序性能的提高非常小。低于1.5。


IIRC服务器虚拟机在启动时做了更多的热点优化,所以它运行得更快,但启动时间稍长,占用更多内存。客户端VM推迟了大部分优化,以允许更快的启动。

编辑补充:这里有一些来自Sun的信息,不是很具体,但会给你一些想法。


IIRC,它涉及到垃圾收集策略。其理论是客户机和服务器在短寿命对象方面是不同的,这对现代GC算法很重要。

下面是服务器模式的链接。唉,他们没有提到客户端模式。

这里有一个关于GC的非常全面的链接;这是一篇比较基础的文章。不确定地址-服务器和-客户端,但这是相关的材料。

在No Fluff Just Stuff, Ken Sipe和Glenn Vandenburg都在这方面做了很棒的演讲。


这实际上链接到HotSpot和默认选项值(Java HotSpot VM Options),这些值在客户端和服务器配置之间是不同的。

从白皮书的第2章(Java HotSpot性能引擎架构):

The JDK includes two flavors of the VM -- a client-side offering, and a VM tuned for server applications. These two solutions share the Java HotSpot runtime environment code base, but use different compilers that are suited to the distinctly unique performance characteristics of clients and servers. These differences include the compilation inlining policy and heap defaults. Although the Server and the Client VMs are similar, the Server VM has been specially tuned to maximize peak operating speed. It is intended for executing long-running server applications, which need the fastest possible operating speed more than a fast start-up time or smaller runtime memory footprint. The Client VM compiler serves as an upgrade for both the Classic VM and the just-in-time (JIT) compilers used by previous versions of the JDK. The Client VM offers improved run time performance for applications and applets. The Java HotSpot Client VM has been specially tuned to reduce application start-up time and memory footprint, making it particularly well suited for client environments. In general, the client system is better for GUIs.

所以真正的区别还在于编译器层面:

The Client VM compiler does not try to execute many of the more complex optimizations performed by the compiler in the Server VM, but in exchange, it requires less time to analyze and compile a piece of code. This means the Client VM can start up faster and requires a smaller memory footprint. The Server VM contains an advanced adaptive compiler that supports many of the same types of optimizations performed by optimizing C++ compilers, as well as some optimizations that cannot be done by traditional compilers, such as aggressive inlining across virtual method invocations. This is a competitive and performance advantage over static compilers. Adaptive optimization technology is very flexible in its approach, and typically outperforms even advanced static analysis and compilation techniques.

注意:jdk6更新10的发布(参见更新发布说明:1.6.0_10中的更改)试图改善启动时间,但原因与热点选项不同,它以不同的方式打包在一个小得多的内核中。


G. Demecki在评论中指出,在64位版本的JDK中,-client选项多年来一直被忽略。 参见Windows java命令:

-client

选择Java HotSpot Client虚拟机。 支持64位的JDK目前忽略了这个选项,而是使用Java Hotspot Server VM。


2022: Holger在评论中引用了JavaSE6 /服务器类机器检测,并补充道:

只有在32位的Windows系统上,-client才会被无条件地选择。 其他系统检查机器是否为“服务器类”,当至少有2个核心和至少2GiB的内存时,这是满足的。 这就解释了为什么在相当长的一段时间内几乎所有东西都使用-server。即使是你能找到的最便宜的电脑,也是“服务器级”机器。Sun/Oracle 64版本甚至没有附带客户端JVM。


我刚刚注意到的一个不同之处在于,在“客户端”模式下,JVM似乎会将一些未使用的内存归还给操作系统,而在“服务器”模式下,一旦JVM获取了内存,它就不会将其归还。这就是它在Solaris和Java6上的显示方式(使用prstat -Z查看分配给进程的内存数量)。


在旧版本的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的最新版本已经删除了标志,并删除了服务器和客户端之间的许多区别。

还要记住,您可以使用jvisualvm查看正在运行的jvm的所有细节。如果您的用户或模块设置JAVA_OPTS或使用脚本更改命令行选项,那么这很有用。这也可以让你实时监控堆和永久空间的使用情况以及许多其他统计数据。


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

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

选择“Java HotSpot Client”虚拟机。支持64位的jdk目前忽略了这个选项,而是使用Java HotSpot Server VM。

然而(为了让事情变得有趣),在-server下它声明:

选择Java热点服务器虚拟机。在支持64位的jdk上,只支持Java HotSpot Server VM,因此-server选项是隐式的。这可能会在未来的版本中更改。

服务器类机器检测页面提供了根据操作系统和体系结构选择虚拟机的信息。

我不知道这其中有多少适用于JDK 6。


上次我看了这个,(不可否认,这是一段时间以前了)我注意到的最大区别是在垃圾收集方面。

IIRC:

服务器堆VM与客户端VM具有不同的代数,并且使用不同的垃圾收集算法。这可能不再是真的了 服务器虚拟机将分配内存,不释放给操作系统使用 服务器VM将使用更复杂的优化算法,因此有更大的优化时间和内存需求

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

我有一对屏幕截图,很好地显示了差异,但我不能再现,因为我有一个64位JVM,它只实现了服务器VM。(我也懒得在我的系统上下载和争论32位版本。)

这种情况似乎不再是这样了,尝试在服务器和客户端vm的windows上运行一些代码,我似乎得到了相同的生成模型…


当从1.4版本迁移到1.7版本(“1.7.0_55”)时。我们在这里观察到的是,在客户端和服务器模式下,分配给heapsize|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

1.7版本的ThreadStackSize更高,而在开放JDK论坛上,有讨论指出1.7版本的帧大小略高。 人们相信,在运行时可以根据应用程序的行为来度量真正的差异


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--) {
        }
    }
}

注意:代码只编译过一次!这两个运行中的类是相同的!

客户端: java.exe -client -classpath C:\mywork\classes com.blogspot. sdoulder . looptest 花费时间:766

-服务器: java.exe -server -classpath C:\mywork\classes com.blogspot. sdoulder . looptest 时间:0

似乎更积极的优化服务器系统,删除循环,因为它知道它不执行任何操作!

参考


来自Goetz - Java并发实践:

Debugging tip: For server applications, be sure to always specify the -server JVM command line switch when invoking the JVM, even for development and testing. The server JVM performs more optimization than the client JVM, such as hoisting variables out of a loop that are not modified in the loop; code that might appear to work in the development environment (client JVM) can break in the deployment environment (server JVM). For example, had we “forgotten” to declare the variable asleep as volatile in Listing 3.4, the server JVM could hoist the test out of the loop (turning it into an infinite loop), but the client JVM would not. An infinite loop that shows up in development is far less costly than one that only shows up in production.

清单3.4。数羊。 挥发布尔睡眠; ... 而(!睡着了) countSomeSheep ();

我的重点。YMMV