代码之家  ›  专栏  ›  技术社区  ›  amit

大型应用程序的JVM性能调整

  •  29
  • amit  · 技术社区  · 15 年前

    默认的JVM参数不适合运行大型应用程序。从那些在真正的应用程序上调优它的人那里获得的任何见解都是有用的。我们在32位Windows计算机上运行应用程序,其中使用的是客户端JVM。 by default . 我们增加了服务器,并将新的比率改为1:3(一个更大的年轻一代)。

    您尝试过并发现有用的其他参数/调整吗?

    [更新]我所说的特定类型的应用程序是一个很少关闭的服务器应用程序,至少需要-xmx1024m的时间。还假设已经对应用程序进行了分析。我正在寻找一般的指导方针 JVM性能 只有。

    7 回复  |  直到 15 年前
        1
  •  17
  •   Jifeng Zhang    11 年前

    周围有大量的信息。

    首先,在调优JVM之前对代码进行概要分析。

    第二,阅读 JVM documentation 小心点,周围有很多“城市传说”。例如,-server标志只在jvm保持常驻并运行一段时间时有帮助;-server“打开”jit/hotspot,并且需要有多个通道通过同一路径才能打开。-服务器,另一方面, 减慢 JVM的初始执行,因为有更多的设置时间。

    附近有几本好书和网站。例如,请参见, http://www.javaperformancetuning.com/

        2
  •  23
  •   user5994461    8 年前

    前言

    背景

    去过爪哇店。整个月都致力于在分布式系统上运行性能测试,主要应用程序是Java。其中一些暗示了由Sun自己开发和销售的产品(然后是Oracle)。

    我将回顾我学到的经验教训,一些关于JVM的历史,一些关于内部的讨论,一些解释的参数,最后一些调优。试着保持它的重点,这样你可以在实践中应用它。

    在Java世界里,事情正在快速变化,所以它的一部分可能已经过时了,因为去年我已经完成了所有这些。(Java 10已经退出了吗?)

    良好做法

    你应该做的是:基准,基准,基准!

    当您真正需要了解性能时,您需要执行实际的基准测试,具体到您的工作负载。别无选择。

    也, 您应该监视JVM。启用监视。 好的应用程序通常提供监控网页和/或API。否则就有了常见的Java工具(JVisualVM、JMX、HPROF和一些JVM标志)。

    请注意,通过调优JVM通常无法获得性能。 . 更多的是 “是否崩溃,找到过渡点” . 就是知道当你付出 那个 应用程序的资源量,您可以一直期望 那个 作为回报的演出数量。 知识就是力量。

    性能主要取决于您的应用程序。如果你想要更快,你必须写更好的代码。

    大部分时间你会做什么:在可靠的敏感默认值下生活

    我们没有时间来优化和优化每一个应用程序。大多数情况下,我们只会忍受合理的违约。

    配置新应用程序时要做的第一件事是阅读文档。大多数重要的应用程序都附带了性能调优指南,包括有关JVM设置的建议。

    然后可以配置应用程序: JAVA_OPTS: -server -Xms???g -Xmx???g

    • -server :启用完全优化(此标志在当前大多数JVM上是自动的)
    • -Xms -Xmx :设置最小堆和最大堆(两者的值总是相同的,这是唯一要做的优化)。

    干得好,你知道所有关于JVM的优化参数,祝贺你! 很简单:d

    你不该做的,永远:

    请不要复制您在Internet上找到的随机字符串,尤其是当它们采用这样的多行时:

    -server  -Xms1g -Xmx1g  -XX:PermSize=1g -XX:MaxPermSize=256m  -Xmn256m -Xss64k  -XX:SurvivorRatio=30  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled  -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=10  -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark  -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -Dsun.net.inetaddr.ttl=5  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=`date`.hprof   -Dcom.sun.management.jmxremote.port=5616 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC
    

    例如,在谷歌的第一页上发现的这件事是非常可怕的。指定的参数有多个值冲突的倍数。有些只是强制使用JVM默认值(最终是2个JVM版本之前的默认值)。一些是过时的,只是被忽视了。最后,至少有一个参数是如此的无效,以至于在启动时,它只因存在而不断地崩溃JVM。

    实际调谐

    如何选择内存大小:

    从你的应用程序中阅读指南,它应该给出一些指示。监控生产,然后进行调整。如果需要精确性,执行一些基准测试。

    重要注意事项 JAVA进程将占用 最大堆加10% . x%的开销是堆管理,不包括在堆本身中。

    所有内存通常在启动时由进程预先分配。您可能会一直看到使用max heap的进程。这根本不是真的。 您需要使用Java监视工具来查看真正使用的是什么。

    找到合适的尺寸:

    • 如果它在内存不足的情况下崩溃,则内存不足
    • 如果不是因为内存不足而崩溃,那就是内存太多了
    • 如果它的内存太多,但是硬件得到了它并且/或者已经支付了,那么它就是 很完美 数字,任务完成!

    jvm6是青铜,jvm7是金,jvm8是白金…

    JVM正在不断改进。垃圾收集是一件非常复杂的事情,有很多非常聪明的人在处理它。在过去的十年里,它有了巨大的进步,并且将继续这样做。

    仅供参考。在Oracle Java 7-8(热点)和OpenJDK 7-8中,它们至少有4个可用的垃圾收集器。(其他JVM可能完全不同,例如Android、IBM、Embedded):

    • 序列代数
    • 并行GC
    • 当前标记扫描GC
    • G1GC
    • (加上变量和设置)

    [从Java 7开始,向前。Oracle和OpenJDK代码部分共享。GC应该(大部分)在两个平台上是相同的。]

    jvm>=7有许多优化和选择合适的默认值。它在平台上有点变化。它平衡多个事物。例如,决定是否启用多核优化CPU是否具有多核。你应该让它去做。 不要更改或强制GC设置。

    让电脑为你做决定是可以的(这就是电脑的作用)。最好是让jvm设置一直保持95%的最佳状态,而不是在所有的盒子上强制“总是8核的攻击性集合以减少暂停时间”,其中一半最终是t2.小的。

    例外 :当应用程序附带性能指南和特定的调优时。完全可以保留提供的设置。

    小费 :为了从最新的改进中获益,迁移到一个新的JVM有时可以提供一个很好的提升,而不需要太多的努力。

    特殊情况:-xx:+usecompressedoops

    JVM有一个特殊的设置,强制在内部使用32位索引(读:类似指针)。允许地址为4_294_967_295对象*8字节地址=>32 GB内存。(不要与实际指针的4GB地址空间混淆)。

    它减少了总体内存消耗,对所有缓存级别都有潜在的积极影响。

    现实生活的例子 :ElasticSearch文档指出,根据内存中保存的实际数据,运行的32GB 32位节点可能等同于40GB 64位节点。

    关于历史的笔记 :在java-7之前的时代(甚至可能是java-6之前),这个标志是不稳定的。它在新的JVM中已经运行了一段时间了。

    Java HotSpot™Virtual Machine Performance Enhancements

    在Java SE 7中,使用压缩OOP是64位JVM进程的默认值,当未指定Xmx时,对于Xmx的值小于32千兆字节。对于6D23发布之前的JDK 6,使用Java命令使用-XX:+UeCopExpSodoOPS标志来启用该特性。

    :再次说明,与手动调优相比,JVM领先多年。不过,知道这一点很有趣=)

    特殊情况:-xx:+usenuma

    非均匀存储器存取(NUMA)是一种用于多处理的计算机存储器设计,存储器存取时间取决于相对于处理器的存储器位置。来源: Wikipedia

    现代系统具有极其复杂的内存结构,跨内核和CPU具有多层内存和缓存,无论是私有的还是共享的。

    很明显,在当前处理器中访问二级缓存中的数据要比从另一个套接字一直访问内存条快得多。

    我相信所有的多重- 插座 今天销售的系统设计上是麻木的,而不是所有的消费者系统。使用命令检查服务器是否支持NUMA numactl --show 在Linux上。

    numa-aware标志告诉JVM为底层硬件拓扑优化内存分配。

    性能提升可能很大(即两位数+xx%)。事实上,如果有人从“非numa 10cpu 100gb”切换到“numa 40cpu 400gb”,如果他不知道这个标志,他可能会在性能上遭受[巨大的]损失。

    注释 :有讨论要检测NUMA并在JVM中自动设置标志。 http://openjdk.java.net/jeps/163

    奖金 :所有打算在大型胖硬件(即NUMA)上运行的应用程序都需要进行优化。它不特定于Java应用程序。

    面向未来-xx:+useg1gc

    垃圾收集的最新改进是 G1 collector (read: Garbage First) .

    它适用于高核、高内存系统。绝对最小4核+6 GB内存。它的目标是使用10倍以上的数据库和内存密集型应用程序。

    短版本,在这些大小下,传统的GC面临着太多的数据,无法一次处理,暂停也变得难以控制。g1将堆分成许多小部分,这些小部分可以在应用程序运行时独立并行地进行管理。

    第一版于2013年推出。它已经足够成熟,现在可以生产了,但不会很快成为违约。对于大型应用来说,这值得一试。

    请勿触摸:发电机组尺寸(NewGen、PermGen…)

    GC将内存分成多个部分。(不涉及细节,你可以谷歌“Java GC代”)。

    上一次,我花了一周时间在一个应用程序上尝试20种不同的代标记组合,每秒点击10000次。我得到了一个巨大的提升,从-1%到+1%。

    Java GC生成是一个有趣的话题来阅读论文或写一篇文章。除非你是1%的人中的一员,他们可以花大量时间在1%真正需要优化的人身上获得微不足道的收益。

    结论

    希望这能对你有所帮助。和JVM玩得开心。

    Java是世界上最好的语言和最好的平台!去传播爱:d

        3
  •  7
  •   TofuBeer    15 年前

    看看这里(或者谷歌搜索热点调优) http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

    在你尝试调优虚拟机之前,你肯定想对你的应用进行分析。NetBeans内置了一个很好的分析器,可以让你看到各种各样的东西。

    我曾经有人告诉我,他们的应用程序的gc被破坏了——我查看了代码,发现他们从未关闭过任何数据库查询结果,所以他们保留了大量的字节数组。一旦我们关闭结果,时间从超过20分钟和GB的内存增加到大约2分钟和非常少量的内存。他们能够删除JVM的调优参数,一切都很顺利。

        4
  •  1
  •   Peter Lawrey    15 年前

    我建议您在配置应用程序的同时打开CPU采样和对象分配监视。你会发现你会得到非常不同的结果,这有助于调整你的代码。也可以尝试使用内置的hprof分析器,它也可以给出非常不同的结果。

    一般来说,分析应用程序比JVM参数有更大的区别。

        5
  •  1
  •   mmDonuts    15 年前

    回答这个问题的最佳方法是在尽可能靠近“生产”环境的地方对应用程序执行控制测试。很有可能,使用-server、合理的起始堆大小和最近的JVM的相对智能行为的行为会比通常尝试的大多数设置表现得更好或更好。

    对于这种广泛的概括,有一个特定的例外:在您在Web容器中运行的情况下,您很可能希望增加永久生成设置。

        6
  •  1
  •   stones333    12 年前

    Java在32位Windows机器上,您的选择是有限的。根据我的经验,以下参数设置将影响应用程序性能:

    1. 内存大小
    2. GC收集器的选择
    3. 与GC收集器相关的参数
        7
  •  0
  •   Gary    15 年前

    这将高度依赖于您的应用程序、供应商和JVM的版本。你需要清楚你认为什么是性能问题。您是否关心代码的某些关键部分?你对这个应用程序做了简介吗?JVM是否花费了太多时间收集垃圾?

    我可能从-verbose:gc jvm选项开始观察垃圾收集是如何工作的。很多时候,最简单的修复方法就是使用-xmx增加最大堆大小。如果您学习了解释-verbose:gc输出,它将告诉您几乎所有关于调优整个JVM的知识。但单独这样做并不会神奇地使调优不当的代码更快地运行。大多数JVM调优选项的设计都是为了提高垃圾收集器和/或内存大小的性能。

    我喜欢分析 yourkit.com