为什么Java对象必须是8的倍数?

我知道Java使用填充; 对象必须是8个字节的倍数。 但是,我没有看到它的目的。 它是干什么用的? 它的主要目的究竟是什么?

它的目的是对齐 ,允许以某些空间为代价更快地访问内存。 如果数据未对齐,则处理器需要在加载内存后进行一些移位以访问它。

此外,垃圾收集简化(并加速),最小分配单元的大小。

Java不太可能需要8个字节(64位系统除外),但由于在创建Java时32位架构是常态,因此Java标准中可能需要4字节对齐。

接受的答案是推测(但部分正确)。 这是真正的答案。

首先,对于@ U2EF1来说,8字节边界的好处之一是8字节是大多数处理器上的最佳访问。 但是,决定还有更多。

如果你有32位引用,你可以寻址最多2 ^ 32或4 GB的内存(实际上你会得到更少,更像是3.5 GB)。 如果你有64位引用,你可以寻址2 ^ 64,这是terrabytes的内存。 但是,对于64位引用,一切都会变慢并占用更多空间。 这是由于处理64位的32位处理器的开销,并且由于更少的空间和更多的垃圾收集,在所有处理器上有更多的GC周期。

因此,创建者采取了中间立场并决定使用35位引用,这允许最多2 ^ 35或32 GB的内存并占用更少的空间,因此具有32位引用的相同性能优势。 这是通过采用32位参考并在读取时将其向左移位3位并在存储参考时将其右移3位来完成的。 这意味着所有对象必须在2 ^ 3个边界(8个字节)上对齐。 这些被称为压缩的普通对象指针或压缩的oops。

为什么不使用36位引用来访问64 GB内存? 嗯,这是一个权衡。 你需要大量的浪费空间来进行16字节对齐,据我所知,绝大多数处理器都没有从16字节对齐中获得速度优势,而不是8字节对齐。

请注意,除非最大内存设置为大于4 GB,否则JVM不会使用压缩oops,默认情况下不会。 您实际上可以使用-XX:+UsedCompressedOops标志启用它们。

这是在32位虚拟机的当天,以便在64位系统上提供额外的可用内存。 据我所知,64位虚拟机没有限制。

来源:Java性能:权威指南,第8章

Java中的数据类型大小是8 (而不是字节)的倍数,因为大多数现代处理器中的字大小是8位的倍数:16位,32位,64位。 通过这种方式,可以使对象中的字段适应(“对齐”)一个或多个字,并尽可能少地浪费空间,利用底层处理器的指令来操作字大小的数据。