【发布时间】:2010-08-23 13:11:59
【问题描述】:
我知道 Java 集合非常需要内存,我自己做了一个测试,证明 4GB 勉强足以将几百万个 Integers 存储到 HashSet 中。
但是如果我有“足够”的记忆呢? Collection.size() 会发生什么?
编辑:已解决:Collection.size() 在超出整数范围时返回 Integer.MAX。
新问题:如何确定那么集合的元素呢?
注意 1:抱歉,这可能是一个让我用谷歌搜索你的问题,但我真的什么也没找到 ;)
注意 2:据我了解,集合的每个整数条目是:
reference + cached_hashcode + boxed_integer_object + real_int_value,对吧?
注意 3:有趣的是,即使使用 JDK7 和“压缩指针”,当 JVM 使用 2GB 的实际内存时,它在 VisualVM 中仅显示 1.5GB 分配的内存。
对于那些关心的人:
测试来源:
import java.util.*;
import java.lang.management.*;
public final class _BoxedValuesInSetMemoryConsumption {
private final static int MILLION = 1000 * 1000;
public static void main(String... args) {
Set<Integer> set = new HashSet<Integer>();
for (int i = 1;; ++i) {
if ((i % MILLION) == 0) {
int milsOfEntries = (i / MILLION);
long mbytes = ManagementFactory.getMemoryMXBean().
getHeapMemoryUsage().getUsed() / MILLION;
int ratio = (int) mbytes / milsOfEntries;
System.out.println(milsOfEntries + " mil, " + mbytes + " MB used, "
+ " ratio of bytes per entry: " + ratio);
}
set.add(i);
}
}
}
执行参数:
在 OpenSuse 11.3 x64 下使用 x64 版本的 JDK7 build 105 进行测试。
-XX:+UseCompressedOops -Xmx2048m
输出结果:
1 mil, 56 MB used, ratio of bytes per entry: 56
2 mil, 113 MB used, ratio of bytes per entry: 56
3 mil, 161 MB used, ratio of bytes per entry: 53
4 mil, 225 MB used, ratio of bytes per entry: 56
5 mil, 274 MB used, ratio of bytes per entry: 54
6 mil, 322 MB used, ratio of bytes per entry: 53
7 mil, 403 MB used, ratio of bytes per entry: 57
8 mil, 452 MB used, ratio of bytes per entry: 56
9 mil, 499 MB used, ratio of bytes per entry: 55
10 mil, 548 MB used, ratio of bytes per entry: 54
11 mil, 596 MB used, ratio of bytes per entry: 54
12 mil, 644 MB used, ratio of bytes per entry: 53
13 mil, 827 MB used, ratio of bytes per entry: 63
14 mil, 874 MB used, ratio of bytes per entry: 62
15 mil, 855 MB used, ratio of bytes per entry: 57
16 mil, 902 MB used, ratio of bytes per entry: 56
17 mil, 951 MB used, ratio of bytes per entry: 55
18 mil, 999 MB used, ratio of bytes per entry: 55
19 mil, 1047 MB used, ratio of bytes per entry: 55
20 mil, 1096 MB used, ratio of bytes per entry: 54
21 mil, 1143 MB used, ratio of bytes per entry: 54
22 mil, 1191 MB used, ratio of bytes per entry: 54
23 mil, 1239 MB used, ratio of bytes per entry: 53
24 mil, 1288 MB used, ratio of bytes per entry: 53
25 mil, 1337 MB used, ratio of bytes per entry: 53
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
最终使用了大约 2 GiB 的实际内存,而不是显示的 1.3 GiB,因此每个条目的消耗甚至大于 53 个字节。 p>
【问题讨论】:
-
我相信你会想要改变你“自己做了一个测试,证明 4GB 勉强足以将几百万个整数存储到一个 HashSet”的断言——我的生产服务会下降几秒钟内就结束了,这几乎是真的。
-
@unhillbilly: 你认为我在撒谎吗? ;) 编辑了我的问题:粘贴了我的测试代码和我的结果。您可以自己测试,然后告诉我们您的结果和测试环境。 -
现在真正的问题是什么 - 1) 当大小大于
Integer.MAX时,int size()会返回什么,或者 2) 为什么不能在 Set 中存储超过 2500 万个整数? -
@matt b:您没有正确阅读:1)size()在元素数量为 Integer.MAX 或更大时返回 Integer.MAX。 2)您可以存储更多元素,这只是我的测试,因为它超出了给定的内存限制而终止。在我的问题中,我提出了计算每个条目所需的内存量的建议。测试证明了这一点:每个整数 53 个字节,而“本机”大小为 4 个字节。 -
@unhillbilly: 1) 错字:4G/56 ~= 71M,不是 17M。 2)对不起,我不明白,你能解释一下吗?什么花了什么?
标签: java memory collections integer overflow