如果我要对32位以上的对象进行更多的引用,会发生什么?

Kac*_*aye 6 java memory-management reference integer-overflow

所以我刚刚学会了声明Object类型的变量(即Object a;)时,为该变量分配了32位空间.在这个变量/引用中,有一个实际Object的内存地址.

现在让我们假装我有足够的内存来做这件事.

如果我创建了超过4,294,967,296(2 32)个Object类型的变量并尝试将它们分配给不同的对象会发生什么?由于整数溢出,某些变量/引用是否会获得相同的内存地址?这意味着在内存中引用超过4,294,967,296个对象是不可能的?

Ste*_*n C 3

所以我刚刚了解到,当您声明一个 Object 类型的变量(即 Object a; )时,会为该变量分配一个 32 位空间。在这个变量/引用内部,有一个实际对象的内存地址。

(当您谈论“32 位空间”时,IT 人员会立即认为您指的是地址空间……而 32 位地址空间为您提供 2^32 字节的存储空间!!)

因此,假设您实际上指的是“32 位空间”,您所说的可能是正确的,也可能是错误的。对于 32 位 JVM,引用确实是 32 位长,这意味着您的程序(理论上)最多可以引用 2^32 个不同的任何类型的对象。即使表示 2^32 个不同的(32 位)引用也将占用 2^34 个字节。

另一方面,如果您在 64 位 JVM 上运行程序,则引用的大小为 64 位,这意味着您的程序(理论上)最多可以引用 2^64 个不同的对象。

但这都是理论上的。问题是在 32 位机器上,您的程序没有足够的内存来表示那么多不同的对象。32 位机器上的最小 Java 对象占用(至少)8 个字节。因此,即使您拥有整个可用地址空间,您也只能表示 2^29 个对象。实际上,操作系统不会为 JVM 提供那么多内存。事实上,根据操作系统的不同,它最多可以获得 4Gb 地址空间中的 2 到 3Gb。


当然,如果您运行 64 位 JVM(在 64 位操作系统/和支持 64 位的硬件上),您就有更大的空间用于对象引用,并且可以有更多的内存来表示它们。但由于硬件限制,您最终仍然会“碰壁”。

值得注意的是,Java 还有其他各种固有的限制。例如,数组最多可以有 2^31 个元素,字符串最多可以有 2^31 个字符,字符串文字最多可以有 2^16 个字符,等等。这些限制比 32 与 64 位参考限制更为基本。


跟进

因此,长话短说,无论我在编译时强制操作系统将多少内存专用于我的程序,总会有一堵预先确定的墙?

那是对的。(有点。你不能强迫操作系统在编译时将内存专用于你的程序。内存大小是在你启动程序时确定的,而不是在编译它时确定的。)基本上,你有以下“旋钮”可以调整...在程序启动时:

  • JVM(32 位与 64 位)对可寻址的内存量进行了限制,并确定引用是 32 位还是 64 位。(请注意,这是一个运行时选择。32 位和 64 位编译的字节码文件是相同的。)

  • -Xms 和 -Xmx 表示堆应该有多大……受到可寻址性和操作系统准备提供给 JVM 进程的内存量的限制。

  • 还有一个与 64 位 JVM 相关的压缩 OOPS功能,但通常默认情况下处于启用状态。