所以我刚刚学会了声明Object类型的变量(即Object a;
)时,为该变量分配了32位空间。在这个变量/引用中,有一个实际Object的内存地址。
现在让我假装我有足够的内存来做这件事。
如果我创建了超过4,294,967,296(2 32 )类型的Object变量并尝试将它们分配给不同的对象,会发生什么?由于整数溢出,某些变量/引用是否会获得相同的内存地址?这意味着在内存中引用超过4,294,967,296个对象是不可能的?
答案 0 :(得分:3)
所以我刚刚学会了声明Object类型的变量(即Object a;)时,为该变量分配了32位空间。在这个变量/引用中,有一个实际Object的内存地址。
(当你谈到“一个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提供那么多内存。实际上,根据操作系统的不同,它可能会获得最多2到3Gb的4Gb地址空间。
当然,如果运行64位JVM(在64位OS /和64位硬件上),则对象引用有更大的空间,并且可以有更多内存来表示它们。但由于硬件限制,你最终还是会“碰壁”。
值得注意的是,Java还有其他各种固有限制。例如,数组最多可包含2 ^ 31个元素,字符串最多可包含2 ^ 31个字符,String literals 限制为2 ^ 16个字符,依此类推。这些限制比32对64位参考限制更为基础。
<强>后续强>
因此,为了缩短长篇故事,无论在编译时我的操作系统将多少内存用于我的程序,总会有一个预定的墙?
这是正确的。 (排序。你不能强迫操作系统在编译时时将内存专用于你的程序。内存大小是在启动程序时确定的,而不是在编译时确定的它。)基本上,你有以下“旋钮”在程序启动时旋转......
JVM(32对64位)限制了可寻址的内存量,并确定引用是32位还是64位。 (请注意,这是运行时选择。编译的字节码文件对于32位和64位是相同的。)
-Xms和-Xmx表示堆应该有多大......受可寻址性限制以及操作系统准备为JVM进程准备的内存量的限制。
还有一个与{64} JVM相关的Compressed OOPS功能,但默认情况下它通常处于启用状态。
答案 1 :(得分:0)
虽然@ rcook的评论对于您的具体示例是正确的,但@Nambari已经触及了如何管理内存的基础知识。如果内存中没有足够的插槽来分配引用,则堆栈将溢出。就像你不能将N+1
元素添加到大小为N
的数组中一样,同样的基本原则也适用。