对于JVM中的类oopDesc,narrowOop的缺点是什么?

时间:2017-02-10 15:32:07

标签: java jvm

我们可以在64位系统中使用压缩的oops(-XX:+ UseCompressedOops),但是压缩的oops只能解决0到4G的排列,因为它是32位宽,所以如果发生了什么?超过4G的所有类空间的总大小?发生异常?

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  }  ;

3 个答案:

答案 0 :(得分:1)

  然而,压缩的oops只能解决0到4G的排列,因为它是32位宽

这是不正确的,因为压缩的oops可以通过利用对象对齐来使用指针压缩

  

那么如果所有类的总大小超过4G,会发生什么?

压缩oops仅引用对象指针,即指向java对象堆的指针。 JVM的类的内部表示(不要与java Class对象混淆)不在对象堆中。它们可能会也可能不会使用自己的压缩指针方案,由单独的UseCompressedClassPointers选项控制。

如果使用了压缩类指针并且压缩的类空间已用完,并且使用最后一个Full GC无法回收空间,那么将会出现OOME。

答案 1 :(得分:0)

首先,您应该将压缩指针区分为java对象(由UseCompressedOops选项启用)和压缩指针klass结构(VM-private结构,存储在...之外)堆并由UseCompressedClassPointers标志控制。

回答原始问题,在arguments.cpp中对JVM启动进行了相应的检查,因此如果压缩指针无法完全解决压缩klass空间,则此选项将被禁用。

还要注意(从问题看起来你有点误解它),即使你只能用32位指针处理4 GB,在JVM中所有对象(和klasses)都对齐8(或更多) ,如果设置了标志ObjectAlignmentInBytes,那么你可以处理32 GB(实际上是4 * logBase2(ObjectAlignmentInBytes))的堆对象。

对齐意味着任何指向object / klass的指针的3个最低位都是零,因此JVM可以“压缩”它们(这就是它们被命名的原因)并在需要时添加它们。 在每个对象访问中,JVM将通过将其移位并存储到64位寄存器中来转换32位指针,然后才从内存中读取(可选择添加指向堆启动的指针)。

因此,在伪代码中JVM将取代64位读取:

Object read(int64 pointer) {
  return (Object) pointer;
}

用这个:

Object read(int32 pointer) {
  int64 ptr = (int64) pointer;
  return (Object) (heapBase + ptr << 3);
}

答案 2 :(得分:0)

压缩OOPS 压缩类指针是两种相关技术,用于减少64位JVM中引用变量的大小。第一个用于减少用户定义的参考变量的大小,而第二个用于减少 JVM定义的参考 变量的大小在64位JVM中调用klass字段(类指针)。

如果您决定使用ObjectAlignmentInBytes VM标志来使用16字节或更高的内存对齐以使用仍然启用压缩OOPS功能的32GB以上,那么您还应该考虑使用填充浪费更多内存的副作用。

您可以阅读Java Performance Optimization: Compressed OOPS本书,了解有关压缩OOPS功能的更多信息。这是让你对压缩的OOPS和压缩类指针有所了解的最好的书。