`
RednaxelaFX
  • 浏览: 3049082 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

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

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

注意:32位HotSpot VM是不支持UseCompressedOops参数的,只有64位HotSpot VM才支持。64位HotSpot VM的版本字符串样子如下:
Java HotSpot(TM) 64-Bit Server VM (build 19.0-b09, mixed mode)


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:
#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:
#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:
#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。
(更新:G1 GC的限制在7017008: G1: Turn on compressed oops by default.已经解除了,于HS21 checkin,也就是说JDK7开始就没有这个限制了。)

第1、3、4点都很直观,于是第2点就是个关键点了:阈值是多大?
还是看回代码,HotSpot 20:
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上有,
ObjectAlignmentInBytes = 8
MinObjAlignmentInBytes = 8
HeapWordSize = 8
MinObjAlignment = 1
MinObjAlignmentInBytesMask = 0x0111
LogMinObjAlignmentInBytes = 3
LogHeapWordSize = 3 // _LP64
LogMinObjAlignment = 0
OopEncodingHeapMax = 0x800000000 // 32GB


于是,前面提到的第2个条件在64位HotSpot VM上默认是:
MaxHeapSize + MaxPermSize + os::vm_page_size() <= 32GB

os::vm_page_size()是操作系统的虚拟内存的分页大小,在Linux上等于sysconf(_SC_PAGESIZE)的值;在x86_64上的Linux默认分页大小为4KB。
MaxHeapSize的值基本上等于-Xmx参数设置的值(会根据分页大小、对齐等因素做调整)。
MaxPermSize就是perm gen设置的最大大小。

注意:通过显式设置-XX:ObjectAlignmentInBytes参数到大于8的值,UseCompressedOops的应用范围可以增加。例如说-XX:ObjectAlignmentInBytes=16能让压缩指针在64GB或以下的GC heap上开启。

这值的计算也曾经RP过:
引用
Changeset: b7268662a986
Author:    coleenp
Date:      2008-04-29 19:31 -0400
URL:       http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/b7268662a986

6689523: max heap calculation for compressed oops is off by MaxPermSize
Summary: Need to subtract MaxPermSize from the total heap size when determining whether compressed oops is turned on.


Oracle的HotSpot VM参数文档里其实也有说UseCompressedOops的使用说明:
引用
-XX:+UseCompressedOops
Enables the use of compressed pointers (object references represented as 32 bit offsets instead of 64-bit pointers) for optimized 64-bit performance with Java heap sizes less than 32gb.

本文只是从源码层确认了该参数自动开启的条件。

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

另外也记了一个gist来看默认情况下JDK6是否开启压缩指针:https://gist.github.com/rednaxelafx/1333043

在VM启动的时候,可以给 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode 参数来确认压缩指针的工作模式。
例子请看:https://gist.github.com/rednaxelafx/998125

HotSpot VM现在只使用3种模式的压缩指针:
1、当整个GC堆所预留的虚拟地址范围的最高的地址在4GB以下的时候,使用"zero based Compressed Oops, 32-bits Oops"模式,也就是基地址为0、shift也为0;
2、当GC堆的最高地址超过了4GB,但在32GB以下的时候,使用"zero based Compressed Oops"模式,也就是基地址为0、shift为 LogMinObjAlignmentInBytes (默认为3)的模式;
3、当GC堆的最高地址超过了32GB,但整个GC堆的大小仍然在32GB以下的时候,使用非零基地址、shift为 LogMinObjAlignmentInBytes (默认为3)的模式。
如果上面三种情况都无法满足,那压缩指针就无法使用了。

上述三种模式的名字在Universe类里有声明:
hotspot/src/share/vm/memory/universe.hpp
  // Narrow Oop encoding mode:
  // 0 - Use 32-bits oops without encoding when
  //     NarrowOopHeapBaseMin + heap_size < 4Gb
  // 1 - Use zero based compressed oops with encoding when
  //     NarrowOopHeapBaseMin + heap_size < 32Gb
  // 2 - Use compressed oops with heap base + encoding.
  enum NARROW_OOP_MODE {
    UnscaledNarrowOop  = 0,
    ZeroBasedNarrowOop = 1,
    HeapBasedNarrowOop = 2
  };


可见,HotSpot VM并不尝试尽量减小shift的数值,而是使用固定数值(与对象对齐相关)或者不做shift。
这点上IBM J9 VM则采取了不同的策略,总是会尝试使用最小的shift值。

==========================================

在64位HotSpot上,不开压缩指针的时候对象头的结构是:
+0:  [ _mark (8 bytes)  ]
+8:  [ _klass (8 bytes) ]
+16: ...


开启压缩指针时:
+0:  [      _mark (8 bytes)             ]
+8:  [      _narrow_klass (4 bytes)     ]
+12: [ padding or first field (4 bytes) ]
+16: ...


==========================================

顺带记几个链接:
HotSpot早期的compressed oops的代码提交
引用
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
Summary: Compressed oops in instances, arrays, and headers. Code contributors are coleenp, phh, never, swamyv
Reviewed-by: jmasa, kamg, acorn, tbell, kvn, rasbold

引用
6689060: Escape Analysis does not work with Compressed Oops
Summary: 64-bits VM crashes with -XX:+AggresiveOpts (Escape Analysis + Compressed Oops)
Reviewed-by: never, sgoldman


引用
6711701: disable compressed oops by default
分享到:
评论
1 楼 xiaoyufu007 2015-12-02  
不太明白32位指针怎么映射到64位的 还请指点~~

相关推荐

    jdk-8u271-windows-x64.exe

    总的来说,JDK 8 Update 271是Java开发者在Windows 64位系统上必不可少的工具,它的特性和改进极大提升了开发效率和代码质量。如果你在Oracle官网上遇到下载问题或速度慢,这个预下载的安装包将是一个方便的选择。

    jdk8u202_linux64位.rar

    本资源“jdk8u202_linux64位.rar”包含了JDK 8 Update 202的Linux 64位版本,是开发者在Linux环境下进行Java编程的重要工具。JDK 8u202被认为是JDK 8的最后一个免费版本,意味着它是公众可以免费下载和使用的最后一...

    jdk-8u131-windows-x64位

    在Windows x64平台上安装JDK 8u131,开发者将能够利用64位系统的性能优势,例如更大的内存访问能力,这对于处理大数据量的应用程序至关重要。此外,64位JDK还支持64位的Java应用,可以更好地满足高性能计算的需求。 ...

    jdk1.8_131 64位安装版

    在这个版本,即JDK 1.8 Update 131,我们主要关注的是针对64位操作系统的版本,它为开发者提供了完整的Java运行环境(JRE)和开发工具,包括Java编译器(javac)、Java虚拟机(JVM)、Java类库以及各种调试和性能...

    最新版windows jdk-8u241-windows-x64.zip 64位

    **Java Development Kit (JDK) 8 Update 241 for Windows 64位详解** JDK(Java Development Kit)是Oracle公司发布的用于开发和运行Java应用程序的重要工具集。在这个最新版的“jdk-8u241-windows-x64.zip”中,...

    jdk-8u311-windows-x64.zip

    这个压缩文件包含了针对64位Windows操作系统的JDK安装程序,`jdk-8u311-windows-x64.exe` 就是执行安装的可执行文件。 JDK 8是Java语言的一个重要里程碑,引入了许多新特性,改进了性能和开发体验。以下是一些主要...

    jdk1.8 64位linux版本

    在多版本JDK共存的情况下,可以使用`alternatives`系统或`update-alternatives`命令来切换默认JDK版本。 6. **安全增强**: JDK 1.8在安全性方面做了许多改进,包括加强证书管理和SSL/TLS协议的安全性。 7. **...

    jdk-8u77-windows-x64.exe

    Java Development Kit(JDK)是Java编程语言的软件...总的来说,Oracle JDK 8 Update 77是Java开发者的重要工具,它的特性改进提升了开发效率和代码质量,尤其对于Windows 64位系统的用户,该版本提供了强大的支持。

    jdk-8u191-linux-x64.tar 下载

    本篇文章将详细讲解JDK 8u191在Linux 64位系统上的下载与安装过程,以及相关的重要知识点。 ### JDK 8u191简介 JDK 8u191是Oracle公司发布的Java 8的更新版本,其中"u191"代表Update 191,即第191次更新。这个版本...

    jdk8-64位-linux版.zip

    本资源是Oracle公司提供的JDK 8的64位Linux版本,具体为JDK 8 Update 251。这个版本的JDK包含了Java运行时环境(JRE)、Java编译器(javac)、Java调试工具(JDB)以及其他开发工具,如jar工具和javadoc。 首先,...

    java8的64位安装包jdk-8u181-windows-x64

    在本例中,我们讨论的是"jdk-8u181-windows-x64"这个特定的安装包,它是Java 8更新181(Update 181)针对Windows操作系统64位平台的版本。 首先,我们需要了解Java 8引入的一些重要特性: 1. **lambda表达式**:这...

    jdk1.8.0_144 (Java SE Development Kit 8u144)

    1. 下载:找到并下载`jdk-8u144-macosx-x64.dmg`文件,这是适用于Mac OS X的64位版本JDK。 2. 安装:双击.dmg文件,按照提示完成安装过程,通常会将JDK安装在 `/Library/Java/JavaVirtualMachines` 目录下。 3. 配置...

    jdk 1.8 免安装版压缩包

    - Oracle官方会定期发布安全更新和补丁,建议保持JDK版本的及时更新,以确保系统的安全性和稳定性。 - 通过`java -update`命令或Oracle官网可以检查并安装最新更新。 通过这些知识点,开发者可以更好地理解和使用...

    java jdk8u64位

    根据提供的文件信息,本文将详细介绍Java JDK 8 Update 64位版本的相关知识点,包括其在Windows 64位系统下的安装与配置方法、新特性介绍以及如何利用这些新特性来提升开发效率。 ### 一、Java JDK 8 Update 64位...

    jdk-8u212-x64(包含linux和windows版本).rar

    在给定的压缩包文件"jdk-8u212-x64"中,包含了适用于两种主流操作系统——Linux和Windows的64位版本。 1. **Java 8的主要特性**: - **Lambda表达式**:这是Java 8最显著的新特性,引入了函数式编程的概念。Lambda...

    JDK8-windows-64

    标题“JDK8-windows-64”所指的是Oracle公司发布的Java Development Kit(JDK)的第8个版本,适用于Windows操作系统的64位环境。JDK是Java编程语言的核心工具集,包含了编译器、调试器、文档生成器以及其他必要的...

    JDK8-8u74-x64

    通过运行这个可执行文件,用户可以在他们的Windows 64位系统上安装JDK8。安装过程中会包含Java运行时环境,以及开发者需要的各种工具,如编译器、调试器、性能分析器等。 2. **readme.txt**:这是一个常见的文本...

    jdk1.8安装版:jdk-8u60-windows-x64

    JDK 1.8 Update 60,也称为 JDK 8u60,是Oracle公司发布的Java平台标准版(Java SE)的一个重要版本,适用于64位Windows操作系统。这个版本的发布是为了提供对Java 8的持续支持,包括性能优化、安全修复和新功能的...

    jdk8u261-linux-x64.tar.gz

    这个版本尤其针对Linux x64架构进行了优化,确保在64位Linux系统上的稳定性和性能。"jdk8u261-linux-x64.tar.gz"是该版本的压缩包文件,采用gzip压缩格式,便于用户下载和解压。 **Java 8基础知识** Java 8是Java...

    jdk-8u241-windows-x64.rar

    标题中的"jdk-8u241-windows-x64.rar"指的是Java Development Kit(JDK)的第241次更新版本,适用于Windows操作系统且为64位架构的压缩文件。JDK是Oracle公司提供的一个核心开发工具集,主要用于编写、调试和运行...

Global site tag (gtag.js) - Google Analytics