在以下测试中:
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("start 1: " + new Date());
Collection collection = new ArrayList();
for (int i = 0; i < 1000 * 1000 * 1000; i++) {
collection.add(new Object());
}
System.out.println("middle 1: " + new Date());
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
iterator.next().toString();
}
System.out.println("\nend 1: " + new Date());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("start 2: " + new Date());
Collection collection = new HashSet();
for (int i = 0; i < 1000 * 1000 * 1000; i++) {
collection.add(new Object());
}
System.out.println("middle 2: " + new Date());
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
iterator.next().toString();
}
System.out.println("\nend 2: " + new Date());
}
});
t1.start();
t2.start();
}
我得到了一个关于ArrayList方法的OutOfMemory。
但是,on this high voted answer,它说HashSet消耗更多内存。 答案中断开的链接看起来像是this one。
我的测试有问题吗?或者,ArrayLists的内存使用率确实比HashSet差?
- 更新:实际上,通过使用collection.add(&#34;。&#34;);我从arrayList获取outOfMemory。但是对于collection.add(new Object());我得到了两个。
答案 0 :(得分:1)
当您想要测量Heap中对象的大小时,一种好的方法是使用优秀的工具SizeOf,它可以让您获得对象的深度大小,这要归功于{{ 1}}。
所以这里举例来说SizeOf.deepSizeOf
只有只有 10百万个对象实例(实际上我没有像你的例子那样拿10亿)需要ArrayList
,如果我设置得当大小为10百万(感谢205 Mo
),它将大小缩小为new ArrayList(size)
。如果190 Mo
无论我设置的是什么大小,都需要HashSet
,所以它会超过两倍。
NB:我在521 Mo
启用了64-Bit JVM
的情况下获得了这些结果。
请注意,大小取决于目标JVM,如果目标JVM是UseCompressedOops
,32-bit JVM
64-bit JVM
(-XX:+ UseCompressedOops),结果确实会改变)默认情况下启用的情况是小于UseCompressedOops
的堆或禁用32 GB
的{{1}}(-XX:-UseCompressedOops)。
答案 1 :(得分:0)
消耗更多内存的Hashsets是有意义的,因为他们需要为潜在的散列值(存储桶)设置空间。现在我不知道它是否消耗了5.5倍的内存(当然这取决于你所存储的对象的性质)但是想到这样的话。 Hashsets是Hashtables,因为arraylists是数组。你将在hashsets中有一些空的空间,这就是消耗额外内存的地方,但对于你正在进行的10亿次迭代,它可能是值得的