JDK默认开启压缩指针问题怎么解决
本文讲解"JDK默认开启压缩指针问题如何解决",希望能够解决您遇到的有关问题,下面我们来看这篇 "JDK默认开启压缩指针问题如何解决" 文章。
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++代码
#ifdef _LP64 // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { if (FLAG_IS_DEFAULT(UseCompressedOops)) { // Turn off until bug is fixed. // the following line to return it to default status. // FLAG_SET_ERGO(bool, UseCompressedOops, true); } // ... } #endif // _LP64
HotSpot 17:
C++代码
#ifndef ZERO #ifdef _LP64 // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { #ifndef COMPILER1 if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) { // Disable Compressed Oops by default. Uncomment next line to enable it. // FLAG_SET_ERGO(bool, UseCompressedOops, true); } } #endif // ... #endif // _LP64 #endif // !ZERO
HotSpot 19 / HotSpot 20:
C++代码
#ifndef ZERO #ifdef _LP64 // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { #ifndef COMPILER1 if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) { FLAG_SET_ERGO(bool, UseCompressedOops, true); } #endif } // ... #endif // _LP64 #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++代码
void set_object_alignment() { // Object alignment. assert(is_power_of_2(ObjectAlignmentInBytes), "ObjectAlignmentInBytes must be power of 2"); MinObjAlignmentInBytes = ObjectAlignmentInBytes; assert(MinObjAlignmentInBytes >= HeapWordsPerLong * HeapWordSize, "ObjectAlignmentInBytes value is too small"); MinObjAlignment = MinObjAlignmentInBytes / HeapWordSize; assert(MinObjAlignmentInBytes == MinObjAlignment * HeapWordSize, "ObjectAlignmentInBytes value is incorrect"); MinObjAlignmentInBytesMask = MinObjAlignmentInBytes - 1; LogMinObjAlignmentInBytes = exact_log2(ObjectAlignmentInBytes); LogMinObjAlignment = LogMinObjAlignmentInBytes - LogHeapWordSize; // Oop encoding heap max OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes; } inline uintx max_heap_for_compressed_oops() { // Avoid sign flip. if (OopEncodingHeapMax < MaxPermSize + os::vm_page_size()) { return 0; } LP64_ONLY(return OopEncodingHeapMax - MaxPermSize - os::vm_page_size()); NOT_LP64(ShouldNotReachHere(); return 0); }
(注:其中 (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++代码
ObjectAlignmentInBytes = 8 MinObjAlignmentInBytes = 8 HeapWordSize = 8 MinObjAlignment = 1 MinObjAlignmentInBytesMask = 0x0111 LogMinObjAlignmentInBytes = 3 LogHeapWordSize = 3 // _LP64 LogMinObjAlignment = 0 OopEncodingHeapMax = 0x800000000 // 32GB
于是,前面提到的第2个条件在64位HotSpot VM上默认是:
C++代码
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功能。
关于 "JDK默认开启压缩指针问题如何解决" 就介绍到这。希望大家多多支持编程宝库。
C#的字符串常量怎么表示:本文讲解"C#的字符串常量如何表示",希望能够解决您遇到的有关问题,下面我们来看这篇 "C#的字符串常量如何表示" 文章。 字符串常量字符串常量是括在双引号 "" 里,或者是括在 @"" 里。字符 ...