Java中的内存开销实际上是什么?

11

我已经阅读了 what-is-the-memory-consumption-of-an-object-in-javawhat-is-the-memory-overhead-of-an-object-in-java,但仍然感到困惑。

  • 什么是内存开销?是指填充吗?
  • 什么是带压缩指针的JVM? 是指引用吗?
  • 如果使用32位JVM,那么开销会更小吗?当然会。但这是因为填充吗?
  • 因此,对于内存效率或性能来说,总是使用32位JVM更好吗?

下面的图像来自此链接(第26页)

在这张图片中,他们一开始就展示了16字节的JVM开销,为什么会这样呢?

enter image description here


1
关于32位和64位JVM:请参见https://dev59.com/9WQm5IYBdhLWcg3w2R_3 - GhostCat
@GhostCat 但如果32位更好地控制内存消耗...那么64位jvm的原因是什么?是因为32位被限制在4GB堆或压缩oops吗? - Prasanna Kumar H A
http://openjdk.java.net/projects/code-tools/jol/ - the8472
现如今,4 GB已经是微不足道的了。有些人这样说;是的,大多数人对使用64位操作系统/应用程序所带来的额外开销并没有什么问题。 - GhostCat
1
@PeterLawrey 很厉害。你8岁的孩子手头上的RAM比我整个家庭都多。但是,我可以超越这一点:5年前我曾经接触过IBM Power系统,它有400GB的RAM。而且我几乎完全能够利用它。 - GhostCat
显示剩余4条评论
1个回答

12

什么是内存开销?

当使用的内存超过您创建的字段时。

这是填充吗?

一些是填充,可以出现在对象中的任何位置,但头部始终位于开头。头部通常为8-12个字节长。

JVM压缩指针是什么?

JVM压缩指针是使用32位指针的64位JVM中的一种技术,可节省内存。

这是引用吗?

引用可以使用此技术,但指向对象的类信息的指针也可以使用。

如果使用32位JVM,则开销会更小吗?

可能是,尽管这与对引用和类使用压缩指针相同。

但是这是因为填充吗?

这是因为64位指针使用的空间比32位指针多。

因此,为了内存效率或性能,总是使用32位JVM更好吗?

不是,32位处理器模型具有32位寄存器,而64位模型具有两倍大小(64位)的寄存器,这意味着可以在最快的内存中保存更多的内容。 64位处理模型的计算速度也往往更快。

总的来说,除非您a)无法使用或b)只有很少量的内存,否则建议始终使用64位JVM。

在这个图片中一开始就显示为16字节的JVM开销,为什么?

这并不严格正确。这假定您具有非压缩的类引用,因此标题为12字节,但默认情况下对象是8字节对齐的,这意味着在结尾处会有4字节的填充(总计16字节,但不全在开头)。

常见问题:为什么32位压缩OOP可以寻址超过4GB的空间?

对象默认需要8字节对齐,这样内存管理更加简单但是有时会浪费一些填充。其副作用是每个对象的地址的最低三位都是0(必须是8的倍数)。这些位不需要存储,这就允许压缩OOP可以寻址8*4GB或32GB的空间。

如果采用16字节对齐,JVM可以使用32位引用来寻址64GB的空间(但是填充开销更大,可能不值得这样做)

常见问题:为什么在28-32GB附近速度变慢?

虽然引用可以乘以8,但堆并不从内存的起始位置开始。通常它从4GB之后开始。这意味着如果要使用全部的32GB,则必须添加此偏移量,这会产生轻微的额外开销。

堆大小:

  • 小于4GB - 零扩展地址
  • 4-28GB - 乘以8或<< 3 注意:x64有一个指令来支持double[]long[]
  • 28-32GB - 乘以8并加上保存偏移量的寄存器。稍微慢一些,但通常不是问题。

1
@Sam 头部信息是对象开头的信息。它包括对象的系统哈希码和类指针,以表示您拥有的对象类型。以下是一些混淆头文件的示例:https://github.com/peter-lawrey/Performance-Examples/blob/master/src/main/java/vanilla/java/unsafe/UnsafeIdentityDemo.java - Peter Lawrey
1
@Sam,你有一个对象头的起始引用。引用的大小和头部(或对象)的大小是不同的。 - Peter Lawrey
1
@Sam 在32位操作系统上需要一个32位JVM。当您拥有28-64 GB等较大的堆时,将64位指针视为32位会产生轻微的开销,但总体上更多、更大的寄存器有助于提高性能。 - Peter Lawrey
1
@Sam 在虚拟机层面上,你只有引用(头文件可能不存在,这是一种实现细节)。揭开JVM所做的事情的面纱,在机器层面上,你只有指针。JVM可以使用技巧将引用转换为指针。 - Peter Lawrey
1
在当今的实现中,String不再具有offset+count字段,因此有一个8字节的对象头(带有压缩的klass指针),加上hashCode+value字段,每个字段4字节(带有压缩的oops),因此总大小为16字节,不需要任何填充。因此,每个String实例占用16字节,而不是过时图形中所说的32字节。Java 9将使用byte[]以便在可行的情况下(实际上大多数字符串)使用8位编码,因此数组大小也将减半... - Holger
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接