老李分享:《Java Performance》笔记2——JVM命令行选项及垃圾收集日志解析

1.JVM命令行选项:

HotSpot VM运行时系统解析命令行选项,并据此配置HotSpot VM,

HotSpot的命令行选项主要有3类:

A. 标准选项:

JVM规范要求所有的JVM都必须实现的选项,它们在发行版之间保持稳定,但也可能在后续的发行版中被废除。如:-client,-server等等。

B. 非标准选项:

以”-X”为前缀,不保证、也不强制所有JVM实现都必须支持,它可能未经通知就在发行版之间发生改变。如:-Xms,-Xmx等等。

C. 非稳定选项:

以”-XX”为前缀,通常是为了特定需要而对JVM的运行进行校正,并且可能需要有系统配置参数的访问权限,也可能不经通知就在发行版之间发生变动。如:-XX:+DisableExplicitGC,-XX:+AggressiveOpts等等。

命令行选项用于控制HotSpot VM的内部变量,每个变量都有类型和默认值。对于内部变量为布尔类型的选项来说,只要在HotSpot VM命令行上添加或去掉它就可以控制这些变量。对于带有布尔标记的非稳定选项来说,选项名前面的”+”或”-”表示true或false。

对于形如-XX:OptionName=<N>的非稳定选项来说,几乎所有附加选项为整数的选项,整数后面都可以接后缀k、m、g,表示千、百万和十亿。

2.32位与64位JVM:

早期的HotSpot VM是32位JVM,内存地址空间限制为4G,但是实际java堆的大小还进一步受限于底层操作系统,随着服务器系统的内存越来越大,64位HotSpot VM应运而生,它可以突破内存地址空间为4G的限制,可以使JVM使用更多的内存,但是随之而来的是64位JVM也带来了性能损失:HotSpot VM内部java对象表示(称为普通对象指针,Ordinary Object Pointers,oops)的长度从32位变为64位,导致CPU高速缓存行(CPU Cache Line)中可用的oops变少,从而降低了CPU缓存命中率,因此导致64位JVM性能通常比32位JVM性能下降约8%~15%。

为了改善64位JVM性能,OpenJDK和HotSpot VM添加了称为压缩指针(Compressed oops)的新特性,使用-XX:CompressedOops命令行选项开启,使得64位JVM性能等于甚至高于32位JVM。

压缩指针是通过对其(Alignment)和偏移量(Offset)将64位指针压缩为32位,即使用了更小更节省空间的压缩指针代替完整长度的64位指针,使得CPU缓存使用率得以提高,从而提高了性能。

此外,在某些平台上(Intel或AMD x64),64位JVM可以使用更多的CPU寄存器,避免寄存器卸载(当活跃状态即变量数目超过CPU寄存器时,多出的活跃状态只能存放在内存中,被称为寄存器卸载),由于CPU寄存器的访问速度高于内存,因此避免寄存器卸载可以让程序运行的更快。

3.CMS垃圾收集过程:

CMS(Concurrent Mark-Sweep GC)是HotSpot VM中的Mostly-Concurrent垃圾收集器,它管理新生代的方式与Parallel收集器和Serial收集器相同,而它在老年代则是尽可能并发执行,每个垃圾收集周期只有两次短的停顿。CMS垃圾收集器分为以下阶段:

A.初始标记:

标记从GC Roots直接可达的老年代对象,需要短暂停顿。

B.并发标记:

标记从初始标记标记的老年代对象可达的存活对象。

C.并发预清除:

为了减少重新标记工作量,完成一些原本在重新标记阶段完成的工作,即重新遍历那些在标记期间因并发而被改掉的对象,可以非常有效地减少重新标记的停顿。

D.重新标记:

因为在并发标记期间应用可能正在运行并更新引用,所以到并发标记结束时,未必所有的存货对象都能确保被标记,因此需要重新标记,即重新遍历所有在并发标记期间有变动的对象并进行最后的标记,追踪更改的对象可以重用数据结构卡表,因为重新标记比初始标记更为重要,因此并发执行以提高效率,需要短暂停顿。

E.并发清除:

清除整个java堆,释放没有迁移的垃圾对象。