为什么创建一个大的Java数组会消耗这么多内存?

4
为什么以下行会导致错误?

    Object[] objects = new Object[10000000];

在JVM中分配数组会导致大量内存(约40M)的使用?是否有任何方法可以了解VM的内部工作方式来分配数组?


1
很多内存是多少?你预计会消耗多少? - Malcolm
2
刚才在回答中已经提到了,如果它是40 MB,那还不算“太多”,对于这么长的引用数组来说,这是一个正常的数量。但如果它是几倍于此的话,那就完全是另外一个问题了。 - Malcolm
你认为一个大小为1000万的数组需要占用多少内存? -1代表不使用你的大脑。 - Erick Robertson
我完全同意你的看法,Erick。 - Manuel Selva
2
但是下次你可以用更委婉的方式表达它。;-) - Manuel Selva
显示剩余2条评论
10个回答

22

这将为10000000个引用分配足够的空间,同时还为数组对象本身分配了一小部分开销。

实际大小取决于虚拟机 - 但它占用相当多的内存并不令人惊讶...我期望至少需要40MB,在64位虚拟机上可能需要80MB,除非它对数组使用压缩指针

当然,如果您用这么多不同的对象填充数组,那将需要更多的内存...但数组本身还需要空间来存放引用。


链接失效了...还有其他的链接吗? - Paul Draper
我找到了一个有效的链接:Java HotSpot™虚拟机性能增强 - user439793

18

“a lot of memory”是什么意思?你分配了10000000个指针,每个指针占用4字节(在32位机器上)-这大约需要40MB的内存。


2
是的...你好,基本数学!它正在占用它应该占用的确切内存量。 - Pete

3
你正在创建一千万个对象的引用。一个引用至少需要4字节;我记得在Java中可能是8字节,但我不确定。
因此,仅凭这一行代码,你就创建了40或80兆字节的数据。

3
你正在为一千万个引用保留空间。这是相当大的一个数量。

3

由于需要为1000万个对象及其相关开销分配堆空间,这导致了大量内存的使用。

如果要了解JVM的内部工作原理,可以查看它的源代码,因为它是开源的。 点击此处


堆空间没有分配,而对象没有使用new创建,是吗? - Manuel Selva
这是一种通用的看法,因为要创建一个对象,你需要使用 new,然后它就会放在堆上。但更具体地说:堆包含对象及其实例变量(包括不是用 new 创建的基本类型)。数组值也放在堆上。 - Jeff
@Manuel Selva:是的,仅当您创建对象时,数组中包含的对象的堆空间才会分配。但是,正如其他答案所解释的那样,数组本身也需要空间来保存对象引用。即使它只包含nulls,数组的空间也会立即分配。 - sleske

3

您的数组必须保存1000万个对象引用,而现代平台上的引用大小为64位(8字节)。由于它是作为一块连续的存储空间分配的,因此应该需要8000万字节。从某种意义上来说,这很大,但与您可能拥有的内存量相比,它很小。为什么它困扰着您呢?


3

它创建了一个包含10,000,000个引用指针的数组,所有引用指针都初始化为null

你觉得这算“很多”吗?


进一步阅读


2

数组被广泛使用的主要原因之一是它们的元素可以在常数时间内访问。这意味着访问a[i]所需的时间对于每个索引i都是相同的。这是因为可以通过将适当的偏移量添加到数组头的地址来算术确定a[i]的地址。原因是分配数组内容的空间作为连续的内存块。


2
根据这个网站,数组的内存使用量为12字节的头部+每个元素4字节。如果你声明了一个空的Object数组,其中包含10M个元素,则从一开始就已经使用了约40MB的内存。如果你开始填充该数组,实际上有10M个对象,则大小会迅速增加。

根据这个网站上的内容,在我的64位机器上进行了测试,一个普通Object的大小约为31字节,因此10M个Object数组的大小只是大约12字节+(4 + 31字节)* 10M = 350,000,012字节(或345.78 MB)。

如果你的数组中包含其他类型的对象,则大小将更大。

如果你必须在程序中保留如此多的数据,我建议你使用某种随机访问文件来保存数据。甚至可以使用数据库,例如Apache Derby,这还能使你对数据进行排序和过滤等操作。


为什么使用"4*31"而不是"4+31"? - Rotsor
哦,是的,已经修好了。谢谢 :) - Yanick Rochon

0

我可能有点落后,但是我从《实用Java》这本书中了解到,向量比数组更高效、更快。那么,是否可以使用向量代替数组呢?


使用向量不会减少资源的占用。事实上,情况可能会更糟,因为向量内部使用数组,而随着插入更多元素,该数组会被重新调整大小 + 1个元素 :) - Yanick Rochon
Java中关于对象内存的讨论很好(与您的评估一致,Yanick)http://www.javaspecialists.eu/archive/Issue029.html - Jerry Carter
你不能说向量总是更有效率 - 这取决于它们的使用方式。向量(更好的说法:列表 - 使用接口)要容易得多(可调整大小,可以在任何地方插入等),因此它们通常更受欢迎。 - sleske

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