Java性能优化全攻略

  让Java应用程序运行是一回事,但让他们跑得快就是另外一回事了。在面对对象的环境中,性能问题就像来势凶猛的野兽。但JVM的复杂性将性能调整的复杂程度增加了一个级别。这里Refcard涵盖了JVM internals、class loading(Java8中更新以映射最新的元空间)、垃圾回收、故障诊断、检测、并发性,等等。

  性能测试工具 Loadrunner

  点击下载

  介绍

  Java是目前软件开发领域中使用最广泛的编程语言之一。Java应用程序在许多垂直领域(银行、电信、医疗保健等)中都有广泛使用。Refcard的目的是,帮助开发者通过专注于JVM内部,性能调整原则和最佳实践,以及利用现有监测和故障诊断工具,来提升应用程序在商业环境中的性能。

  它能以不同的方式定义“optimal performance(最佳性能)”,但基本要素是:Java程序在业务响应时间要求内执行计算任务的能力,程序在高容量下执行业务功能的能力,并具有可靠性高和延迟低的特点。有时,数字本身变得模式化:对于一些大型网站,优秀的页面响应时间应该在500ms以下。在适当的时候,Refcard包括目标数字。但在大多数情况下,您需要根据业务需求和现有的性能基准自己决定这些。

  JVM Internals

  基础知识

物联网

  代码编译和JIT

  编译Java字节码显然没有直接从主机执行本机代码那么快。为了提高性能,Hotspot JVM找出最繁忙的字节码区域,然后将其编译成更高效地原生、机器代码(自适应优化)。然后这种本地代码就会存储在非堆内存中的代码缓存中。

  注意:多数的JVM是通过禁用JIT编译器实现的(Djava.compiler=NONE)。您只需要考虑禁用的关键性优化,比如JVM崩溃。

  下图说明了Java源代码,即时编译流程和生命周期。

物联网

  内存空间

  HotSpot Java Virtual Machine是由以下的存储空间组成。

存储空间描述Java HeapJava程序类实例和数组的主存储器。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中的实例。#FormatImgID_3#确保适当的Permanent Generation / Metaspace和本地内存大小。密切监视你的PermGen、元空间和本机内存利用率,并调整到适合的最大容量。分析程序类加载器的大小,并寻找机会适当地减少元数据足迹。