让Java应用程序运行是一回事,但让他们跑得快就是另一回事了。在面对对象的环境中,性能问题就像来势凶猛的野兽。但JVM的复杂性将性能调整的复杂程度增长了一个级别。这里Refcard涵盖了JVM internals、class loading(Java8中更新以映射最新的元空间)、垃圾回收、故障诊断、检测、并发性,等等。html
Java是目前软件开发领域中使用最普遍的编程语言之一。Java应用程序在许多垂直领域(银行、电信、医疗保健等)中都有普遍使用。Refcard的目的是,帮助开发者经过专一于JVM内部,性能调整原则和最佳实践,以及利用现有监测和故障诊断工具,来提高应用程序在商业环境中的性能。java
它能以不一样的方式定义“optimal performance(最佳性能)”,但基本要素是:Java程序在业务响应时间要求内执行计算任务的能力,程序在高容量下执行业务功能的能力,并具备可靠性高和延迟低的特色。有时,数字自己变得模式化:对于一些大型网站,优秀的页面响应时间应该在500ms如下。在适当的时候,Refcard包括目标数字。但在大多数状况下,您须要根据业务需求和现有的性能基准本身决定这些。git
编译Java字节码显然没有直接从主机执行本机代码那么快。为了提升性能,Hotspot JVM找出最繁忙的字节码区域,而后将其编译成更高效地原生、机器代码(自适应优化)。而后这种本地代码就会存储在非堆内存中的代码缓存中。apache
注意:多数的JVM是经过禁用JIT编译器实现的(Djava.compiler=NONE)。您只须要考虑禁用的关键性优化,好比JVM崩溃。编程
下图说明了Java源代码,即时编译流程和生命周期。windows
HotSpot Java Virtual Machine是由如下的存储空间组成。数组
存储空间 | 描述 |
Java Heap | Java程序类实例和数组的主存储器。 |
Permanent Generation(JDK 1.7及如下版本)Metaspace (JDK 1.8及以上版本) | Java类元数据的主存储器。注意:从Java 8开始,PermGen空间就由元空间和使用本地存储器替换了,相似于IBM J9 JVM。 |
Native Heap(C-Heap) | 本地内存存储线程、栈、包括对象的代码缓存,如MMAP文件和第三方本机库。 |
Java的另外一个重要特色是,在JVM启动以后,它可以加载编译的Java类(字节码)。根据程序的大小,在刚刚重启以后,程序在类加载过程当中性能会显著下降。这种现象是由于内部JIT编译器在重启以后须要从新开始优化。缓存
自JDK 1.7版本以后,有一些改进值得你们重视。例如默认的JDK class loader具备更好的装在类并发能力。安全
关注的区域 | 建议 |
JVM重启后的性能降低 | 避免部署过量的Java类到一个单一的应用程序类加载器(例如:很是大的WAR文件) |
运行时发现过多的类加载争夺(thread lock, JAR file searches…) ,下降了总体性能。 | 分析您的应用程序并识别代码模块进行动态类加载操做过于频繁。积极寻找非一站式类加载错误,如ClassNotFoundException和NoClassDefFoundError。再访Java映射API和适用状况下优化的过分使用。 |
java.lang.OutOfMemoryError: PermGen space (JDK 1.7及如下版本)java.lang.OutOfMemoryError:元空间(JDK 1.8及以上版本) | 再访JVM Permanent Generation、Metaspace (MaxMetaSpaceSize)和本地内存容量在适用状况下的尺寸。分析应用程序类加载器和识别元数据的内存泄漏的源头。 |
目标 | 建议 |
跟踪那些加载到不一样的类加载器的Java类。 | 配置程序选择使用的Java profiler,例如JProfiler或Java VisualVM。将重点放在类加载器的操做和内存占用上。能够经过–verbose:class. for the IBM JVM,生成多个Java核心快照跟踪活动的类加载器和加载类。 |
调查类元数据的内存泄露的能够来源。 | 配置程序和定义可能的culprit(s)。生成并分析JVmheap dump快照,专一于类加载器和java.lang.Class中的实例。
|
确保适当的Permanent Generation / Metaspace和本地内存大小。 | 密切监视你的PermGen、元空间和本机内存利用率,并调整到适合的最大容量。分析程序类加载器的大小,并寻找机会适当地减小元数据足迹。 |
Java垃圾回收流程对于程序性能是相当重要的。为了提供有效的垃圾回收,Heap(堆)本质上是划分在子区域中。并发
区域 | 描述 |
最新一代-Young Generation (nursery space) | 新的或短暂的对象分配保留堆的一部分。垃圾被一个fast but stop-the-world YG的收集器进行回收。
在young space中呆了足够久的对象就会提高到old space。 注意:YG space的尺寸和GC频率太高将会显著影响程序的响应时间,从而致使JVM的暂停时间增长。 |
老一代-Old Generation (tenured space) | heap的一部分留给了long-lived对象。垃圾一般经过平行或并发(多数时候)进行收集,诸如CMS或gencon (IBM JVM)。
性能提示:根据应用程序的需求选择并测试最佳的GC策略是很是重要的。例如,当切换到并发GC收集(如CMS或G1)能够显著提升应用程序的平均响应时间(减小延迟)。 |
选择正确的collector或GC policy能够将程序的性能、可扩展性和可靠性优化到最佳状态。许多应用程序对于响应时间延迟都很敏感,所以大多须要使用并发的回收器,例如HotSpot CMS或IBM GC policy balanced。
咱们强烈建议您经过适当的性能和负载测试肯定最合适的GC策略。应该在生产环境中执行全面监控策略,以跟踪总体的JVM性能,并肯定在以后须要改进的领域。
GC | 论据 | 描述 |
串行回收器 | -XX:+UseSerialGC (Oracle HotSpot) | 不管新旧回收器都使用单独CPU,像是一种stop the world的时尚。
|
并行回收器(吞吐量回收器) | -XX:+UseParallelGC-XX:+UseParallelOldGC (Oracle Hotspot)
-Xgcpolicy:optthruput |
旨在利用CPU的内核优点。不管新旧回收器都使用多个Gcthreads(via –XX:ParallelGCThreads=n),从而更好地利用来自主机的可用的CPU内核来完成。注意:虽然回收时间能够显著减小,可是有着大尺寸堆的程序面临着large、stop-the-world、old回收,而且响应时间也受到影响。
|
确保适当的Permanent Generation / Metaspace和本地内存大小。 | 密切监视你的PermGen、元空间和本机内存利用率,并调整到适合的最大容量。分析程序类加载器的大小,并寻找机会适当地减小元数据足迹。 | 旨在最大限度地减小旧一代stop-the-world回收器对程序响应时间的影响。大多数使用CMS collector的老一代回收器与所述应用程序的执行同时进行。
注意:YoungGen collections仍然有stop-the-world事件,所以须要适当的微调,以减小总JVM暂停时间。 |
HotSpot G1 collector是专为是专为知足用户定义的垃圾回收(GC)高几率暂停时间设计的,同时实现高吞吐量。
最新的HotSpot collector将heap基本划分到一组大小相等的堆区域,虚拟内存的每一个区域连续范围。它将回收压缩的活动集中在heap区域,那里充满了可回收的对象(garbage first)。换句话说就是,这个区域有最低限度的“live”对象。
Oracle建议在如下例子和状况下使用G1 collector,尤为是对于目前正在使用CMS或parallel collectors的:
你必定要知道没有GC策略能够挽救Java Heap尺寸不足的现象。这些演习涉及到为不一样的存储空间(包括新旧不一样的版本)配置最大和最小的容量,包括元数据和本地内存容量。这里有一些建议准则:
目标 | 建议 |
内存大小GC调整
监控和故障排除 |
默认状况下,元空间内存空间是无界的,并使用可用于动态扩展的process或OS native memory。内存空间分红快并经过mmap被JVM进行存储。咱们建议保持默认设置,以动态调整模式为出发点,将简化的尺寸与密切监测的应用程序元数据占有量相结合,从而进行更好的容量规划。新增一个JVM选项(-XX:MaxMetaspaceSize=<NNN>),可让您限制分配给class metadata的本地内存。当面临物理资源(RAM)紧张或相似于内存泄露的状况时,建议将它做为一个保障机制。
对那种具备larger class metadata footprint或dynamic classloading的Java应用程序,咱们建议经过新的JVM选项调整初始元空间大小 :-XX:MetaspaceSize=<NNN>,例如:1GB。这种调整方法将有助于避免包括class metadata在内的早期垃圾回收,尤为是在Java应用程序的 “warm-up”期。 |
目标 | 建议 |
测量和监视应用程序YoungGen和OldGen内存占用,包括GC活动。为您的应用程序决定正确的GC策略和Java堆大小。
调整应用程序的内存占用量,如live对象。 |
分析、监控您所使用的Java分析工具,如JProfiler、Java VisualVM或其余商业APM产品。容许经过–verbose:gc记录JVM GC活动。您也可使用相似GCMV(GC Memory Visualizer)的工具查看JVM的暂停时间和内存分配率。
性能提示:过多的内存分配率可能意味着须要进行垂直和横向扩展,或从多个JVM进程中分离出实时数据。 为了long-lived对象或long-term实时数据考虑,能够生成并分析JVM heap dump快照。Heap dump分析对于程序内存占用(retention)的优化是很是有帮助的。 性能提示:因为从32位到64位,Java应用程序对heap 的需求会比原来高1.5倍。因此,在Java 1.7及如下的版本(这是默认的)中使用 -XX:+UseCompressedOops是很是重要的。这样的参数调整大大减轻了64位JVM的性能压力。 |
调查OutOfMemoryError 问题,寻找OldGen内存泄露的根源。 | 使用相似Java VisualVM、Plumbr的工具(Java内存泄漏检测器),分析可能存在的内容泄露。性能提示:要着重分析最大的Java对象上。要意识到下降内存占有量就意味着提高性能,并下降GC活动。
使用相似 Memory Analyzer的工具生成并分析JVM heap dump快照。 |
Java并发性能够定义为程序同时执行多个任务的能力。对于大型的Java EE系统,这意味着执行多个用户的业务功能的同时,实现最佳的吞吐量和性能的能力。
不管是硬件能力仍是JVM稳定情况,Java并发性问题可能引发程序的瘫痪,严重影响程序的总体性能和可用性。
当您评估Java应用程序的并发线程的稳定情况时,你会常常遇到Thread lock contention的问题,这是目前最多见的Java并发问题。
例如:Thread lock contention会触发non-stop,它会尝试将一个缺乏Java类(ClassNotFoundException的)加载到默认的JDK 1.7 ClassLoader。
若是您在成熟的技术环境中碰见像Thread Dump analysis这样的问题,咱们强烈建议您积极面对它。这个问题的根源一般不一样于以前的Java synchronization to legitimate IO blocking或者其余的non-thread safe calls。Lock contention问题每每是另外一个问题的“症状”。
真正的Java-level deadlocks是不太常见的,它一样能够极大程度地影响应用程序的性能和稳定性。当遇到两个或多个线程永远阻塞的时候,就会触发这样的问题。这种状况不一样于其余常见的那种“day-to-day”线程问题,例如 lock contention、threads waiting on blocking IO calls等等。真正的lock-ordering deadlock问题能够被看作以下:
Oracle HotSpot 和IBM JVM为大多数的deadlock detectors状况提供了解决方案,帮助您快速找出形成这种情况的罪魁祸首的线程。遇到相似lock contention troubleshooting的问题,建议从诸如线程转储分析为出发点来解决该问题。
一旦找到形成问题的代码根源,解决方案涉及lock-ordering条件寻址和来自JDK其余可用的并发编程技术,如java.util.concurrent.locks.ReentrantLock,提供了诸如tryLock()的方法。这种方法给予开发人员更大的灵活性,也为防止deadlock和thread lock “starvation”提供了更多方式。
在进行JVM调优的同时,也有必要检查应用程序的行为,更确切地说是最高clock time和CPU burn的贡献者。
当Java垃圾回收和线程并发再也不是压力点,深刻到你的应用程序代码的执行模式,并专一于顶级响应时间贡献者(也叫做clock time)是很重要的。检查应用程序代码的消CPU耗和Java 线程(CPU burn)也一样相当重要。CPU使用率较高(>75%)是不正常的(良好的物理资源的利用率)。由于这每每意味着效率低下和容量问题。对于大型的Java EE企业应用,保持安全的CPU缓冲区是必要的,以应对突发的负载冲击状况。
摒弃那些传统的跟踪方法,如在代码中加入响应时间“日志”。Java剖析工具和APM解决方案偏偏能够帮助您分析这类型的问题。这种方式更加高效、可靠。对于Java生产环境缺少一个强大的APM解决方案。您仍然能够依赖诸如Java VisualVM的工具,经过多个快照进行thread dump分析,并使用OS CPU分析每一个线程。
最后的建议是,不要妄图同时解决全部的问题。列出排在最前面的5个clock time和CPU burn问题,而后寻找解决方案。
其余关于Java应用程序性能的重要方面是稳定性和可靠性。在有着99.9%典型可用目标的SLA umbrella下,稳定和可靠对于程序的操做尤其重要。这些系统应该具备高容错级别,并对应用和资源进行严格的预算,以防止发生多米诺效应。用这种方法能够防止一些这样的状况,例如,一个业务流程使用全部可用的物理,中间件或JVM资源。
Java application与外部系统之间缺少合理的超时时间,因为中间件和JVM线程消耗(blocking IO calls),可能致使严重的性能降低和中断。合理的超时时间能够避免在遇到外部服务提供商速度缓慢的时候,Java线程等待过久。
目标 | 建议工具 |
自动、实时地性能监控、调节、预警、趋势分析、容量管理,等等 | Enterprise APM solutions(企业级APM解决方案)注意:APM解决方案提供了工具,这些现成的功能让您实现如下大部分的Java性能目标。 |
性能和负载测试 | 商业性能测试解决方案Apache JMeter
|
JVM垃圾回收评估,内存分配率和故障排除 | Oracle Java VisualVMhttp://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/intro.html
http://java.dzone.com/articles/profile-your-applications-java http://www.oracle.com/technetwork/java/javase/jmc53-release-notes-2157171.html IBM Monitoring and Diagnostic Tools for Java (via IBM Support Assistant tool) http://www-01.ibm.com/software/support/isa/ JVM verbose:gc logs JVM argument : -verbose:gc http://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html IBM GCMV |
JVM堆和类的元数据的内存泄漏分析 | Oracle Java VisualVM and Oracle Java Mission ControlIBM Monitoring and Diagnostic Tools for Java
Memory Analyzer (heap dump analysis, hprof and phd formats) https://www.ibm.com/developerworks/java/jdk/tools/memoryanalyzer/ |
JVM内存分析和堆容量评估 | Oracle Java VisualVM and Java Mission ControlIBM Monitoring and Diagnostic Tools for Java
Java profilers (JProfiler, YourKit) http://en.wikipedia.org/wiki/JProfiler Memory Analyzer (heap dump and application memory footprint analysis) |
JVM和中间件并发故障,如thread lock contention和deadlocks | Oracle Java VisualVM and Oracle Java Mission Control (threads monitoring, thread dump snapshots)jstack, native OS signal such as kill -3 (thread dump snapshots)
http://www.oracle.com/technetwork/java/javase/tooldescr-136044.html#gblfh IBM Monitoring and Diagnostic Tools for Java 注意:强烈推荐你们关注如何执行一个JVM线程转储分析的相关知识。 |
Java应用程序clock time分析和评测 | Oracle Java VisualVM and Oracle Java Mission Control (build-in profiler, sampler and recorder)Java profilers (JProfiler, YourKit) |
Java应用程序和线程CPU burn分析 | Oracle Java VisualVM and Oracle Java Mission Control (CPU profiler)Java profilers (JProfiler, YourKit)
注意:必要的时候,您还能够依赖JVM线程转储和OS CPU每一个线程分析。 |
Java IO和remoting contention分析,包括超时管理评估和调整 | Oracle Java VisualVM and Oracle Java Mission Control(threads monitoring, thread dump snapshots)
jstack, native OS signal such as kill -3 (thread dump snapshots) IBM Monitoring and Diagnostic Tools for Java 注意:强烈推荐你们关注如何执行一个JVM线程转储分析的相关知识。 |
中间件,Java EE容器调整,如线程、JDBC数据源,等等 | Oracle Java VisualVM and Oracle Java Mission Control (extra focus on exposed Java EE container runtime MBeans)Java EE container administration and management console |