jav*_*top 8 java memory collections integer overflow
我知道Java集合非常需要内存,并且自己做了一个测试,证明4GB几乎不足以存储数百万的Integers HashSet.
但是,如果我有"足够的"记忆呢?怎么会发生什么Collection.size()?
编辑:已解决:超出整数范围时Collection.size()返回Integer.MAX.
新问题:如何确定集合元素的"真实"数量呢?
注意1:对不起,这可能是一个let-me-google-it-for-you-question,但我真的没有找到任何东西;)
注2:据我了解,一组的每个整数条目是:
reference + cached_hashcode + boxed_integer_object + real_int_value,对吗?
注3:有趣的是,即使使用JDK7和"压缩指针",当JVM使用2GB的实内存时,它只显示1.5GB的内存VisualVM.
对于那些关心的人:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在OpenSuse 11.3 x64下使用x64版本的JDK7 build 105进行测试.
-XX:+UseCompressedOops -Xmx2048m
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
最后,使用了大约2 GiB实内存,而不是显示1.3 GiB,因此每个条目的消耗甚至大于 53字节.
qua*_*oup 14
我知道,Java集合是非常消耗内存,并做了一个测试自己,证明了4GB仅够数以百万计的几个存储
Integers成HashSet.
Java堆!=系统内存.Java的默认堆大小仅为128MB.请注意,这也与JVM使用的内存不同.
关于你的问题:来自文档,
返回此集合中的元素数.如果此集合包含多个
Integer.MAX_VALUE元素,则返回Integer.MAX_VALUE.
您的问题似乎与标题的内容完全不同.
您已在标题中回答了问题(Integer.MAX_VALUE已退回).并且没有:你无法找到普通API的"真实"大小,以便迭代收集和计数(使用long当然).
如果你想存储Set的int值,你知道的范围和值的数量可能会变得非常大,那么BitSet实际上可能是一个更好的实现:
import java.util.*;
import java.lang.management.*;
public final class IntegersInBitSetMemoryConsumption {
private final static int MILLION = 1000 * 1000;
public static void main(String... args) {
BitSet set = new BitSet(Integer.MAX_VALUE);
for (int i = 1;; ++i) {
if ((i % MILLION) == 0) {
int milsOfEntries = (i / MILLION);
long mbytes = ManagementFactory.getMemoryMXBean().
getHeapMemoryUsage().getUsed() / MILLION;
double ratio = mbytes / milsOfEntries;
System.out.println(milsOfEntries + " mil, " + mbytes + " MiB used, "
+ " ratio of bytes per entry: " + ratio);
}
set.set(i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将生成一个恒定大小的数据结构,该结构可以保持范围内的所有值,而不会改变大小并占用相对少量的内存(每个可能值1位加上一些开销).
然而,这种方法有两个缺点:
int值SetAPI通过编写使用两个BitSet对象(可能是懒惰分配)的包装器分别保存正值和负值范围并实现接口的适配器方法,可以很容易地解决这两个问题Set.