首页 文章

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

提问于
浏览
361

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

11 回答

  • 337

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

    来自Chapter 2的白皮书(The Java HotSpot Performance Engine Architecture):

    JDK包括两种VM:一种是客户端产品,另一种是针对服务器应用程序调整的VM . 这两个解决方案共享Java HotSpot运行时环境代码库,但使用适合客户端和服务器的独特性能特征的不同编译器 . 这些差异包括编译内联策略和堆默认值 . 尽管服务器和客户端虚拟机类似,但服务器虚拟机已经过专门调整,以最大限度地提高峰值运行速度 . 它用于执行长时间运行的服务器应用程序,这些应用程序需要尽可能快的运行速度,而不是快速启动时间或较小的运行时内存占用 . 客户端VM编译器用作经典VM和先前版本的JDK使用的实时(JIT)编译器的升级 . 客户端VM为应用程序和小程序提供了改进的运行时性能 . Java HotSpot客户端VM经过专门调整,可缩短应用程序启动时间和内存占用,使其特别适合客户端环境 . 通常,客户端系统更适合GUI .

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

    客户端VM编译器不会尝试执行服务器VM中编译器执行的许多更复杂的优化,但作为交换,它需要更少的时间来分析和编译一段代码 . 这意味着客户端VM可以更快地启动并且需要更小的内存占用 . Server VM包含一个高级自适应编译器,它支持通过优化C编译器执行的许多相同类型的优化,以及传统编译器无法完成的一些优化,例如跨虚拟方法调用的积极内联 . 与静态编译器相比,这是一种竞争优势和性能优势 . 自适应优化技术的方法非常灵活,通常甚至优于高级静态分析和编译技术 .

    注意:jdk6 update 10(参见Update Release Notes:Changes in 1.6.0_10)的发布试图改善启动时间,但由于与热点选项不同的原因,使用更小的内核进行不同的打包 .


    G. Demecki指出in the comments在64位版本的JDK中,多年来忽略 -client 选项 .
    Windows java command

    -client
    

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

  • 5

    旧版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 或使用更改命令行选项的脚本,这将非常有用 . 这还可以让您实时监控堆和permgen空间使用情况以及许多其他统计信息 .

  • 12

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

  • 1

    -client和-server系统是不同的二进制文件 . 它们本质上是两个不同的编译器(JIT),它们连接到同一个运行时系统 . 客户端系统最适合需要快速的应用程序启动时间或占地面积小,服务器系统最适合整体性能最重要的应用 . 通常,客户端系统更适合GUI等交互式应用程序

    enter image description here

    我们用两个开关运行以下代码:

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

    Note: 代码只编译一次!两次运行中的类都相同!

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

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

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

    Reference

  • 3

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

    在Windows的java – the Java application launcher页面上,在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选项是隐式的 . 这可能会在将来的版本中发生变化 .

    Server-Class Machine Detection页面提供有关OS和体系结构选择的VM的信息 .

    我不知道这对JDK 6有多大帮助 .

  • 25

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

    编辑添加:来自Sun的Here's some info,它不是非常具体,但会给你一些想法 .

  • 14

    来自Goetz - 实践中的Java并发:

    调试提示:对于服务器应用程序,请务必在调用JVM时始终指定-server JVM命令行开关,即使是用于开发和测试 . 服务器JVM执行比客户端JVM更多的优化,例如从循环中提取变量而不在循环中修改;可能看起来在开发环境(客户端JVM)中工作的代码可能在部署环境(服务器JVM)中中断 . 例如,如果我们“遗忘”在清单3.4中将变量声明为volatile,则服务器JVM可以将测试从循环中提升(将其转换为无限循环),但客户端JVM则不会 . 在开发过程中出现的无限循环远远低于仅在 生产环境 中出现的循环 . 清单3.4 . 算羊 . volatile boolean asleep; ... while(!asleep)countSomeSheep();

    我的重点 . 因人而异

  • 20

    IIRC,它涉及垃圾收集策略 . 理论上说,客户端和服务器在短期对象方面会有所不同,这对现代GC算法很重要 .

    Here is a link在服务器模式下 . 唉,他们没有提到客户端模式 .

    Here is a very thorough link一般关于GC;这是more basic article . 不确定是否地址-server vs -client,但这是相关材料 .

    在No Fluff Just Stuff,Ken Sipe和Glenn Vandenburg都在就这类事情进行了很好的讨论 .

  • 31

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

  • 84

    上次我看过这个,(并且不可否认它已经有一段时间了)我注意到的最大区别在于垃圾收集 .

    IIRC:

    • 服务器堆VM具有与客户端VM不同的代数,以及不同的垃圾收集算法 . This may not be true anymore

    • 服务器VM将分配内存,而不是将其释放到操作系统

    • 服务器VM将使用更复杂的优化算法,因此对优化有更大的时间和内存要求

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

    我有一对屏幕截图显示差异非常好,但我无法重现,因为我有一个64位JVM只实现了服务器VM . (而且我也不会在我的系统上下载和纠缠32位版本 . )

    这似乎不再是这种情况,尝试在服务器和客户端虚拟机的Windows上运行一些代码,我似乎得到了相同的生成模型对彼此而言...

  • 1

    当从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
    

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

相关问题