2007年6月15日星期五

HotSpot内存管理 [笔记]

Memory Management in the Java HotSpot Virtual Machine
whitepaper
Sun Microsystems
April 2006

本文描述J2SE 5发布版JVM中可用的垃圾回收器,并给出垃圾回收器选择和配置的优化建议。
首先针对显式内存管理和自动内存管理的比较进行简短的讨论。表明显式内存管理所带来的挂起引用和内存泄漏两大主要问题,在现代面向对象语言中广泛应用的自动内存管理能够解决此类问题,自动管理的功能通过垃圾回收器实现。
然后说明垃圾回收器的基本概念。垃圾回收器负责分配内存,保证所有被引用着的对象在内存中,回收垃圾内存。垃圾回收能够解决大部分内存分配问题,但不是全部,比如无限创建对象并长久使用直至内存耗尽,同时垃圾回收本身是非常耗费资源的复杂任务。设计和选择垃圾回收算法时需要作出一些选择:串行抑或并行,并发抑或中止,紧凑、非紧凑抑或拷贝,等等。垃圾回收器的性能指标包括:吞吐量、时间开销、中止时间、回收频率、空间开销、回收速度,等等。当采用分代回收技术时,内存按照年龄被划分为很多代,针对不同代应用不同的垃圾回收算法。

J2SE 5.0 update 6版本的HotSpot JVM中有4个垃圾回收器,均采用分代技术。HotSpot将内存组织为三代:young、old和permanent。大多数对象最初分配在young区域,经历若干次回收仍保留下来的转到old区域,一些大的对象可能直接分配在old区域,permanent区域保存着描述类、方法的对象以及类、方法信息,便于垃圾回收器方便管理。
当young区域装满时,执行young代回收,当old或permanent区域装满时执行全回收,一般先对young代进行回收,然后由一个回收器同时对old和permanent代执行old代回收算法。如果需要执行紧凑算法,每个代分别进行。
为了加速分配,HotSpot采用了简单的bump-the-pointer技术,保存先前分配对象的末地址,便于连续分配,减少碎片。对于多线程应用程序,分配操作必须是线程安全的,如果用全局锁则将降低性能,HotSpot采用了Thread-Local Allocation Buffers (TLABs)技术,给每一个线程分配私有缓冲区用于内存分配,提高多线程分配吞吐量。

当使用Serial回收器时,young和old回收均采用串行、中止方式,管理的内存空间较小,一般用于客户端应用程序,它们没有最小化中止时间的需求。这是缺省的垃圾回收器。显式选择方式为-XX:+UseSerialGC。
Parallel回收器的开发目的是为了充分利用多核CPU,适用于具有多个CPU的机器,并且要运行的程序没有最小化中止时间的需求。此回收器已被Parallel Compacting回收器取代。
Parallel Compacting回收器在update 6版本引入,与上一个回收器的区别在于old代垃圾回收过程采用了新的算法。此回收器不仅能够充分利用多CPU,而且减少了中止时间。但它不适于large shared机器(如SunRays),此类机器上没有任何一个应用程序能够独占长时间独占多个CPU,这时可以考虑减少垃圾回收所用的线程数(-XX:ParallelGCThreads=n)或者选择其他的回收器。显式选择方式为-XX:+UseParallelOldGC。
Concurrent Mark-Sweep (CMS)回收器用于解决如下问题:对于许多应用,快速的响应时间比端到端的传输更重要;young代回收一般不会引起长时间程序中止,而old代回收虽不频繁但会造成长时间中止,特别是管理较大内存时。如果应用程序所占用的常驻内存较大,并且运行在多个CPU的机器上,比如web服务器,则适用此回收器。对于运行在单核机器上、占用中等大小常驻内存的交互式应用程序,它也能优化其运行性能。显式选择方式为-XX:+UseConcMarkSweepGC。如果希望以增长模式运行,则需要再开启-XX:+CMSIncrementalMode选项,适用于有最小化中止时间需求而所在机器只有一两个CPU。

垃圾回收器的选择、heap大小、HotSpot虚拟机(客户端抑或服务器)的选择都是自动完成的,基于应用程序所在的平台、操作系统。J2SE 5.0发行版引入了垃圾回收动态调优的新方法,称为ergonomics,目的是用最少的命令行参数达到性能优化的效果。用户指定所需要的行为,垃圾回收器动态调整各个heap区大小以达到需求目标。
服务器的定义为具有2个以上物理CPU,2G以上物理内存,此定义适用于所有平台,除了运行Windows的32位平台。
在非服务器机器上运行时,缺省参数为client JVM, serial回收器,初始heap大小为4M,最大heap大小为64M。
在服务器上运行时,JVM缺省为server版,缺省的回收器为parallel回收器,除非显式指定-client选项,此时回收器缺省为serial回收器。初始heap大小为1/64物理内存大小,最大值为1G,最大heap大小为1G。

推荐开始时让系统自动选择优化,测试应用系统的性能是否可以接受。出现性能障碍时,首先需要调整的是垃圾回收器的选择,根据性能度量、分析工具的输出结果调整选项,控制heap大小或垃圾回收行为等。
除非出现长时间中止的情形,尝试分配尽量大的heap大小。吞吐量是与可用内存量成比例的,具有足够的可用内存是影响垃圾回收性能的最大影响因素。
确定最大内存量之后,可以考虑调整不同代的大小。影响回收性能的第二大因素是young代比例。原则是尽量多地分配内存给young代,除非出现old代回收超时或较长的中止时间的情形。如果采用serial回收器,young代大小不能过半。如果采用某种parallel回收器,指定期望行为是更好的方式,而不是直接指定确切的heap大小。

垃圾回收性能的评测工具:
• -XX:+PrintGC
• -XX:+PrintGCDetails
• -XX:+PrintGCTimeStamps
• jmap
• jstat
• HPROF (JDK5)
• HAT (JDK5)
http://java.sun.com/j2se/1.5/pdf/jdk50_ts_guide.pdf
http://java.sun.com/developer/technicalArticles/Programming/HPROF.html
https://hat.dev.java.net/

没有评论: