JDK从6 update 23开始在64位系统上会默认开启压缩指针

开发 后端
如题。先前都没仔细留意,今天在看一个crash log的时候才发现这点,记录一下。 本来以为这个是在6 update 25才开始开启的…

如题。先前都没仔细留意,今天在看一个crash log的时候才发现这点,记录一下。

本来以为这个是在6 update 25才开始开启的…

Sun的HotSpot VM从JDK5开始会根据运行环境来自动设定VM的一些参数(ergonomics)。其中大家最熟悉的可能是它会自动选择client与server模式、堆的初始和***大小等。事实上ergonomics会设置非常多的内部参数,包括自动选择GC算法、并行GC的线程数、GC的工作区分块大小、对象晋升阈值等等。

Ergonomics相关的逻辑大都在hotspot/src/share/vm/runtime/arguments.cpp中,值得留意的是使用了FLAG_SET_ERGO()的地方。

于是我们可以留意一下几个版本的HotSpot对UseCompressedOops参数的处理的差异:

HotSpot 16:

C++代码

  1. #ifdef _LP64     
  2.   // Check that UseCompressedOops can be set with the max heap size allocated     
  3.   // by ergonomics.     
  4.   if (MaxHeapSize <= max_heap_for_compressed_oops()) {     
  5.     if (FLAG_IS_DEFAULT(UseCompressedOops)) {     
  6.       // Turn off until bug is fixed.     
  7.       // the following line to return it to default status.     
  8.       // FLAG_SET_ERGO(bool, UseCompressedOops, true);     
  9.     }     
  10.     // ...     
  11.   }     
  12. #endif // _LP64    

 

HotSpot 17:

C++代码

  1. #ifndef ZERO     
  2. #ifdef _LP64     
  3.   // Check that UseCompressedOops can be set with the max heap size allocated     
  4.   // by ergonomics.     
  5.   if (MaxHeapSize <= max_heap_for_compressed_oops()) {     
  6. #ifndef COMPILER1     
  7.     if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) {     
  8.       // Disable Compressed Oops by default. Uncomment next line to enable it.     
  9.       // FLAG_SET_ERGO(bool, UseCompressedOops, true);     
  10.     }     
  11.   }     
  12. #endif     
  13.   // ...     
  14. #endif // _LP64     
  15. #endif // !ZERO    

 

HotSpot 19 / HotSpot 20:

C++代码

  1. #ifndef ZERO     
  2. #ifdef _LP64     
  3.   // Check that UseCompressedOops can be set with the max heap size allocated     
  4.   // by ergonomics.     
  5.   if (MaxHeapSize <= max_heap_for_compressed_oops()) {     
  6. #ifndef COMPILER1     
  7.     if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) {     
  8.       FLAG_SET_ERGO(bool, UseCompressedOops, true);     
  9.     }     
  10. #endif     
  11.   }     
  12.   // ...     
  13. #endif // _LP64     
  14. #endif // !ZERO 

 

(注:HotSpot VM的版本号与JDK的版本号之间的关系,请参考另一篇笔记:Sun/Oracle JDK、OpenJDK、HotSpot VM版本之间的对应关系)

可以看到,UseCompressedOops参数从HotSpot 19开始终于开始受ergonomics控制,会在下述条件满足的时候默认开启:

1、是64位系统(#ifdef _LP64)并且不是client VM(#ifndef COMPILER1);

2、Java堆的***大小不大于一个阈值(MaxHeapSize <= max_heap_for_compressed_oops());

3、没有通过.hotspotrc或命令行参数手动设定过UseCompressedOops参数的值;

4、没有使用Garbage-First (G1) GC。

第1、3、4点都很直观,于是第2点就是个关键点了:阈值是多大?

还是看回代码,HotSpot 20:

C++代码

  1. void set_object_alignment() {     
  2.   // Object alignment.     
  3.   assert(is_power_of_2(ObjectAlignmentInBytes), "ObjectAlignmentInBytes must be power of 2");     
  4.   MinObjAlignmentInBytes     = ObjectAlignmentInBytes;     
  5.   assert(MinObjAlignmentInBytes >= HeapWordsPerLong * HeapWordSize, "ObjectAlignmentInBytes value is too small");     
  6.   MinObjAlignment            = MinObjAlignmentInBytes / HeapWordSize;     
  7.   assert(MinObjAlignmentInBytes == MinObjAlignment * HeapWordSize, "ObjectAlignmentInBytes value is incorrect");     
  8.   MinObjAlignmentInBytesMask = MinObjAlignmentInBytes - 1;     
  9.     
  10.   LogMinObjAlignmentInBytes  = exact_log2(ObjectAlignmentInBytes);     
  11.   LogMinObjAlignment         = LogMinObjAlignmentInBytes - LogHeapWordSize;     
  12.     
  13.   // Oop encoding heap max     
  14.   OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes;     
  15. }     
  16.     
  17. inline uintx max_heap_for_compressed_oops() {     
  18.   // Avoid sign flip.     
  19.   if (OopEncodingHeapMax < MaxPermSize + os::vm_page_size()) {     
  20.     return 0;     
  21.   }     
  22.   LP64_ONLY(return OopEncodingHeapMax - MaxPermSize - os::vm_page_size());     
  23.   NOT_LP64(ShouldNotReachHere(); return 0);     
  24. }    

 

(注:其中 (uint64_t(max_juint) + 1) 的值也被称为NarrowOopHeapMax,也就是2的32次方,0x100000000;

ObjectAlignmentInBytes在64位HotSpot上默认为8;

HeapWord在globalDefinitions.hpp里定义,大小跟一个char*一样;

HeapWordSize在同一个文件里定义,等于sizeof(HeapWord),在64位系统上值为8;

LogHeapWordSize也在同一文件里,在64位系统上定义为3)

跟踪一下里面几个参数的计算,在64位HotSpot上有,

C++代码

  1. ObjectAlignmentInBytes = 8     
  2. MinObjAlignmentInBytes = 8     
  3. HeapWordSize = 8     
  4. MinObjAlignment = 1     
  5. MinObjAlignmentInBytesMask = 0x0111     
  6. LogMinObjAlignmentInBytes = 3     
  7. LogHeapWordSize = 3 // _LP64     
  8. LogMinObjAlignment = 0     
  9. OopEncodingHeapMax = 0x800000000 // 32GB    

 

于是,前面提到的第2个条件在64位HotSpot VM上默认是:

C++代码

  1. MaxHeapSize + MaxPermSize + os::vm_page_size() <= 32GB   

 

os::vm_page_size()是操作系统的虚拟内存的分页大小,在Linux上等于sysconf(_SC_PAGESIZE)的值;在x86_64上的Linux默认分页大小为4KB。

MaxHeapSize的值基本上等于-Xmx参数设置的值(会根据分页大小、对齐等因素做调整)。

MaxPermSize就是perm gen设置的***大小。

这下可以确认,在我现在用的环境里,当包括perm gen在内的GC堆大小在32GB - 4KB以下的时候,使用64位的JDK 6 update 23或更高版本就会自动开启UseCompressedOops功能。

【编辑推荐】

  1. Java 7将于明年7月28日正式发布面向开发者
  2. Java 7,一个技术标准的商业咒语
  3. Java 7 未按时发布 计划再次延期
  4. Oracle和JCP成员之间的Java战争一触即发
  5. IBM加入OpenJDK 将联手Oracle发展Java技术
责任编辑:金贺 来源: ITEYE博客
相关推荐

2013-09-05 10:47:49

Ubuntu 13.1

2024-03-28 10:40:43

javanew关键字

2009-08-11 09:24:03

Windows 764位计算

2013-06-08 10:13:13

64位ARM服务器

2009-12-17 10:05:07

LinuxdtAgeiaPhys

2009-09-25 13:33:08

2015-12-15 15:27:37

NginxHTTP网络协议

2023-06-01 08:25:19

Windows 10Tiny10

2020-11-03 06:55:41

系统版本64位

2014-03-19 13:14:35

AMD64位ARM数据中心

2012-08-15 10:24:32

JavaJava 7

2011-07-28 09:42:58

Windows 764位32位

2012-05-29 10:47:36

Windows 7操作系统

2021-03-02 15:02:07

Windows 7微软操作系统

2012-12-26 13:39:47

2013-10-31 16:31:19

2023-10-11 18:35:20

Java编程语言

2010-07-12 09:14:17

Windows 864位32位

2022-02-11 17:45:47

Raspberry操作系统树莓派

2010-12-17 17:25:22

Office 2010
点赞
收藏

51CTO技术栈公众号