4

我想问一下 java 中的内存开销,我有一个很大的 ArrayList(61,770 个项目),并试图通过分析应用程序来计算每个项目占用的内存量(计算对象及其 ArrayList 条目)我得到了加载所有数据后,堆占用约 25Mb。当 ArrayList 只有 2 个项目时,堆占用 ~1Mb ,大致如下:

(24*1024*1024)/61,768 = 407 字节。

但是,当我计算每个对象的字段时,我得到 148 个字节(不包括 ArrayList,并且假设 int=4,float=4,reference=4),我很想知道所有这些额外字节是从哪里来的从...

我可以猜测,由于我存储在 ArrayList 中的对象正在实现一个接口,它们存储了额外的值,也许 VM 为每个实现的方法存储了一个 4 字节的函数指针?他们实现的接口有 20 个函数,因此增加了 80 个字节,总共 228 个字节,仍然没有接近测量的 400 个字节。

任何帮助,将不胜感激。


哇,感谢所有伟大的答案。

@Bolo:感谢链接,我用这个类测量每个对象约 350 个字节,所以我至少可以确认大量内存使用的来源。

@Yuval A:感谢您的介绍,这是一个宝贵的信息来源。

@Ukko:注意点。

@Jayan:现在当我尝试转储堆时,NetBeans 分析器给我错误,稍后再试。

4

5 回答 5

6

这些结果并不令人惊讶。JVM 为每个对象增加了大量的开销。

由于 JVM 内存开销,单个对象的预期大小大约是预期大小的两倍并不少见。

该演示文稿对 Java 中的各种数据结构内存使用进行了精彩、深入的解释和概述。

于 2010-04-27T13:18:09.577 回答
2

ArrayList 通常大于元素的数量。用于getCapacity()获取底层数组的当前大小。

于 2010-04-27T13:14:51.620 回答
2

您的方法的一个大问题是与垃圾收集器的交互。它基本上使您提出的任何测试从外部完全不透明。

作为一个思想实验,如果你想这样做,你应该

  1. 启动您的 JVM 并执行几次全局 GC 以清除所有垃圾
  2. 测量堆大小和 Java 关于它有多少可用空间的概念。
  3. 运行你的测试
  4. GC几次
  5. 重做第 2 步的测量

在所有这些和一些数学之后,你会更接近但仍然不对。唯一真正的解决方案是像其他人提到的那样实际询问实现。或者从实现的知识中弄清楚。

于 2010-04-27T13:21:14.590 回答
1

arraylist 消耗的内存有点模糊。

在适当的阶段对进程进行堆转储 - 在完全分配值之后。然后使用内存分析器(来自 eclipse)之类的工具。

您填充查找浅层和保留堆大小。

于 2010-04-27T13:11:54.040 回答
0

附带说明一下,既然您确切地知道 ArrayList 中有多少对象,为什么不直接使用 array[] 呢?里面的物体数量会改变吗?

于 2010-04-27T14:19:39.007 回答