6

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

现在让我们假设我有足够大的内存来执行此操作。

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

4

2 回答 2

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 相关的Compressed OOPS功能,但它通常默认启用。

于 2013-07-15T04:14:44.567 回答
0

虽然@rcook 对您的具体示例的评论是正确的,但@Nambari 已经触及了内存管理的基础知识。如果内存中没有足够的插槽来分配引用,那么堆栈将溢出。就像您无法将N+1第 th 个元素添加到 size 数组N一样,同样的基本原则也适用。

于 2013-07-15T03:03:12.493 回答