边缘问题
在某些场景下,按照前面的一步步优化指导无法产生效果。这一节说明一下这些情况。
一些应用分配了一些少量的非常大的长时间存活的对象。这样的场景需要需要young代的空间比old代更大。
一些应用会经历很少的对象转移。这样的场景可能需要old代的空间远远大于存活对象的大小,由于old的占用量增长率很小。
一些应用有小延迟需求,会使用CMS垃圾回收器,而且使用小young代空间(以致于MinorGC时间更短),以及大的old代空间。在这种配置下,对象会快速的从young代移动到old代,替代了高效老化对象。另外,CMS垃圾回收移动后的对象,碎片的可能性通过大的old代空间来解决。
下一节介绍一些其他的HotSpot VM选项来提升应用的性能。
其他一些的性能命令行选项
几个可选的前面有提到的命令选项可以用来提升Java应用的延迟和吞吐量性能,这些选项是通过JIT编译器代码优化以及其他的HotSpot VM优化能力。下面介绍这些特性以及相适应的命令选项。
最新和最大优化
当新的性能优化集成到HotSpot VM中之后,可以通过-XX:+AggressiveOpts选项来启用。
通过选项来引入新的优化,可以把最新及最大的优化和以及经过长时间使用证明是稳定的优化分离开。应用通常更希望获得更好的稳定性,毕竟最新的优化可能会导致未知的问题。但是如果应用需要提升任何可以提升的性能优化的时候,可以使用命令选项来启用这些优化。
当新的优化被证明是稳定的之后,他们会被默认使用,也许需要升级几个版本之后才会变成默认。
使用
-XX:+AggressiveOpts命令选项之后,需要考虑到性能的提升,同样也需要考虑到性能提升所带来的不稳定风险。
逃避分析
逃避分析是一个种分析Java对象范围的技术,在特殊情况下,一个线程分配的对象可能被另外一个线程使用,这个对象就叫着“逃避”。如果对象没有逃避,额外的优化技术可以应用,因此,这种优化技术叫做逃避分析。
在HotSpot VM里面的逃避分析优化可以通过命令行选项:
-XX:+DoEscapeAnalysis
这是在Java 6 update 14中引入的,而且自动启用通过-XX:+AggressiveOpts。在Java 6 update 23中是默认开启的。
通过逃避分析,HotSpot VM JIT编译器,可应用下面的优化技术:
1、
对象爆炸:
对象爆炸是一种对象的属性存储在Java堆以外而且可能潜在的消失。比如说,对象属性可以直接被放置到内存的寄存器里面或者对象被分配栈里面而不是堆里面。
分等级替换:分等级替换是一种用来减少内存使用的优化技术,考虑下面的Java类,表现为保存长方形的长和宽:
public class Rectangle {
int length;
int width;
}
HotSpot VM可以优化内存分配和使用非逃避的Rectangle类的实例通过把长和宽都直接存储到CPU的寄存器而不是分配Rectangle对象,结果是当时需要使用长和宽属性的时候,不需要再复制到CPU的寄存器。这个可以减少内存的读取。
2、
线程栈分配:
顾名思义,线程栈分配是一种把对象分配到线程栈中,而不是Java堆里面的优化技术。一个对象永远不逃避,就可以放置到线程栈框架里面,由于没有其他线程需要看到这个对象。线程栈分配可以减少对象分配到Java堆,可以减少GC的频率。
3、
消灭同步:
如果线程分配的对象从来不会逃避,而且这个线程锁定了这个对象,这个锁可能会被JIT编译器消灭,毕竟没有其他线程会使用这个对象。
4、
消灭垃圾回收读写障碍
:如果线程分配的对象从来不会逃避,只会被当前线程使用,所以在其他对象里面存储它的地址不需要障碍。读或者写障碍只有在对象会被其他线程使用的时候才有需要。
有偏见的锁
有偏见的锁是使得锁更偏爱上次使用到它线程。在非竞争锁的场景下,即只有一个线程会锁定对象,可以实现近乎无锁的开销。
有偏见的锁,是在Java 5 update 6引入的。通过HotSpot VM的命令选项-XX:+UseBiasedLocking启用。
Java 5 HotSpot JDK需要明确的命令来启用这个特性,在使用-XX:+AggressiveOpts选项,有偏见的锁会Java 5中会被自动启用。在Java 6中是默认启用的。
各种经历告诉我们这个特性对大多数应用还是非常有用的。然后,有一些应用使用这个属性不一定能够表现的很好,比如,锁被通常不被上次使用它的同一个线程使用。对于Java应用来说,由于stop-the-world安全点操作需要取消偏见,这样可以通过使用-XX:-UseBiaseLocking来获得好处。如果你不清楚你的应用是什么情况,可以通过分别设置这两个选项来测试。
大页面
在计算机系统中,内存被分为固定大小的区块,这个区块就叫做页(page)。内存的存取是通过程序把虚拟内存地址转换成物理内存地址实现的。虚拟到物理地址是在一个块表里面映射的。为了减少每次存取内存的时候使用页表的消耗,通常会使用一种快速的虚拟到物理地址转换的缓存。这个缓存叫做转换后备缓冲区(translation lookaside buffer),简称TLB。
通过TLB来满足虚拟到物理地址的映射请求,会比遍历页表来找到映射关系快很多,一个TLB通常包含指定数量的条目。一个TLB条目是一个基于页大小虚拟到物理地址映射,因此,更大的页大小允许一个条目或者一个TLB有更大的内存地址范围。在TLB中有更广泛的地址,更少的地址转换请求在TLB中不命中,就可以减少遍历页表(page table)操作。使用大页的目的就是减少
TLB的
不命中。
Oracle solariz,Linux 以及Windows都支持HotSpot VM使用大页。通常处理器可以支持几种页大小,不过不同的处理器各不相同。另外,操作系统配置需要使用大页。
下面说说怎么样在Linux下使用大页(Large Page)
Linux下的大页面
在写作本书的时候,在Linux下使用大页,除使用-XX:+UseLargePages
命令选项以外,
需要
修改
操作系统配置。Linux的修改操作具体和发行版本以及内核有关系。为了合理的启用Linux下的大页,可以征询Linux管理员的意见或者阅读Linux发行文档。一旦使用了Linux操作系统配置已经修改,
-XX:+UseLargePage
命令行选项就必须要使用了。比如:
$ java -server -Xmx1024m -Xms1024m -Xmn256m -XX:+UseLargePages ...
如果大页没有被合理设置,HotSpot VM同样会接受
-XX:+UseLargePages是一个有效的选项,不过会报告无法获取大页,而且会退回操作系统的默认页大小。
PS:打完收工,其实翻译挺无聊和挺累的
我的网站:
赶驴记
赶驴记