JVM(和Spark)性能优化:使用Java Mission Control (8)
5 性能优化编码
有同事说按他们的经验大数据开发的问题(包括性能)中有50%是由参数配置不当造成的。这有一定道理,因为现在的大数据堆栈的参数实在太多了,像Apache Spark,实际上要理解Hadoop(HDFS、YARN)、Spark、JVM等众多参数设置。这些在网上(包括hi上)有一些帖子总结了一些经验。
关于大数据的性能优化编码方面,还较少,这儿我总结一些。
首先参见《Java语言编程规范 上卷 综合篇》的性能与资源管理。
无线OSS PAI/PRS项目是一个Scala/Spark/Java混合的项目,碰到过一些棘手问题,其中一个是JVM线程阻塞。通过观察了几天线程阻塞在哪儿,为什么阻塞,发现这个时候通常在做GC。而他们的集合有近一亿条记录...GC压力很大。打个比方,全网100万部手机,每个手机几秒钟上报一次测量报告,要把这些东东收集起来分析。不断采集,海量数据。
虽然今天的JVM已经很聪明了,但还不够聪明。要尽量写GC友好的代码:
1、显式地在finally块中关闭file和socket io。但在Java 7中,可以使用try-with-resource。
2、慎用显式地调用Object.wait/notify方法、以及lock方法;慎用synchronized关键字。锁的粒度、释放顺序等,容易造成死锁、活锁、线程饥饿等现象。
优先使用Future/Promise、Dataflow、CSP、Actor模型、Agent、STM等并发范型。
3、大对象、大集合--尤其是其中的元素也是个复杂对象时,当不再使用时,要显式地释放内存,提供destroy/depose/clear方法(调用内部集合的clear方法、变量设为null)。
大集合或StringBuilder/StringBuffer等设置好初始大小并尽量复用。例如HashMap在创建时可以设置为numberOfEntries/0.75避免经常性地resize分配内存: new HashMap<>( (int)Math.ceil(numberOfEntries/0.75))。如果需要用排序的TreeMap,它有个构造方法TreeMap(Map m), 可以把HashMap转换过来。 于是,可以先创建个HashMap,填充完entry后,再转换排序。
4、深层嵌套组合对象(一个对象中new另一个对象、此对象再new另一个对象...),可以改为延迟lazy(Scala中直接有此关键字)创建,例如用工厂方法模式、服务定位器模式,在Java中,还可以使用javax.inject的@Provider
5、适当地使用weak和soft引用对象。
6、Scala的HashMap可以尝试用java.util.ConcurrentHashMap代替,尤其是在Java 8,后者的性能得到极大提升。甚至Eclipse Collections等第三方集合库。
6 后记
还有其它免费的工具,例如Oracle Solaris Studio,它包括三个组件Performance Analyzer、Code Analyzer、Thread Analyzer,下载地址:http://www.oracle.com/technetwork/server-storage/solarisstudio/downloads/index.html。Performance Analyzer是一个非常强大的工具,其功能不限分析Java应用,也能用于分析员基于C\C++\Fortran的应用程序。既可以分析Java代码也可以分析本地代码。能够支持SUSE Linux Enterprise等。
开源免费的GCView是一个可视化垃圾收集日志分析的小工具。
免费的内存分析工具Eclipse Memory Analyzer(MAT),此文Android最佳性能实践(二)——分析内存的使用情况 有个很好的介绍。
另一个广泛使用的工具是JProfiler,有10天的试用版:http://www.ej-technologies.com/products/jprofiler/overview.html 。
jClarity的两个工具,有14天试用版。它不仅仅提供了数据收集功能和可视化,对于检测到的问题,这两个工具能够提供具有实践性强的建议,帮助开发人员去解决问题。
Takipi的 建立基于一个简单的目的:告诉开发人员到底在何时什么原因代码出现异常。每当一个新的异常抛出,或者一个错误日志发生,Takipi就会捕获它,给用户展 示可能引起该异常的变量状态,经过的方法和设备。Takipi在错误发生时刻将会覆盖实际执行代码—所以在你分析异常时,就如同当异常发生时你正好在场。
Java技术既有工业界Oracle、IBM等庞大人力和巨额资金的扶持,也有学术界著名计算机科学家像Doug Lea等Rock Star的鼎力开发,其JVM采用了最先进的技术号称最强大的语言虚拟机,它的优势在于运行期的动态优化,充分利用现代CPU/GPU/存储和OS等的体系结构(例如现代CPU的CAS、AVX2指令等)。有人说,同等经验的程序员(例如5年),用Java开发的效率和性能比C++等要好,开发现代多核、分布式系统,有5年Java经验的程序员,如果用C++开发,可能要有8年以上经验才能相当。当然C++在开发操作系统、驱动程序、办公软件等传统领域还是挺有用的。
在《Java程序员修炼之道》(及其它一些著作)中,6.6节 HotSpot的JIT编译的“为什么要动态编译” P163写到:动态编译会给编译器提供更多信息。具体地说,提前(AOT)编译的语言(像C++)得不到运行时的任何信息—比如某个指令是否可用,其它的硬件细节及代码运行情况的统计数据。这些变数让事情变得很有趣,使得Java这样的动态编译语言实际上可能会比提前编译的语言运行得更快。
JVM的动态(编译)优化有五花八门的大胆优化,包括乱序/重排序执行、锁优化(自旋锁、锁消除、锁粗化、轻量级锁、偏旋锁)、最前沿的优化技术之一逃逸分析(优化:栈上分配、同步消除、标量替换)、最重要的优化技术之一方法内联(比AOT更智能)、独占调用(派发)允许Java平台进行C++这种AOT语言实现不了的优化(P165)。
JavaOne 2014年大会,有来自100个国家9010位参会者。Java早已经不是上世纪90年代的Java了。
7 参考资料
7.1 JMC官方文档:http://docs.oracle.com/javacomponents/jmc.htm
Java Flight Recorder Runtime Guide,http://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/index.html
7.2 Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#G1Options
7.3 Presentations
Using Java Flight Recorder, Marcus Hir
Java Mission Control & Java Flight Recorder, M. ISURU T. C. PERERA
Tuning Java for hadoop-code mash 2015,Scott Seighman
What’s New in HotSpot JVM 8, Vladimir Ivanov
7.4 Books
Java Performance: The Definitive Guide,Scott Oaks,2014
Java程序员修炼之道,Benjamin J. Evans,Martijn Verburg,英文版2013
Java性能优化权威指南,Charlie Hunt,Binu John,英文版2012
- 点赞
- 收藏
- 关注作者
评论(0)