仓蓝

日记本

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  23 Posts :: 0 Stories :: 1 Comments :: 0 Trackbacks
   JAVA之JDK在64位系统默认开启压缩指针分析(请多多指正!)
      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++代码

    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++代码

  • 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功能


    posted on 2012-03-02 11:07 cangshi 阅读(2244) 评论(0)  编辑  收藏 所属分类: java

    只有注册用户登录后才能发表评论。


    网站导航: