我们可以在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;
} ;
答案 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和压缩类指针有所了解的最好的书。