ArrayList vs HashSet,哪个对内存性能更好?
ArrayList vs HashSet, which is better for memory performance?
在下面的测试中:
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 消耗更多内存。
答案中损坏的 link 看起来像是 this one.
我的测试有问题吗?或者 ArrayLists 在内存使用方面真的比 HashSet 更差?
--更新:实际上,通过使用 collection.add(".");我从 arrayList 中获取 outOfMemory。但是对于 collection.add(new Object());我两个都买。
哈希集消耗更多内存是有意义的,因为它们需要为潜在的哈希值(桶)设置空间。现在我不知道它是否消耗了 5.5 倍的内存(当然这取决于您存储的对象的性质)但可以这样想。哈希集之于哈希表就像数组列表之于数组一样。您将在哈希集中有一些空白空间,这就是消耗额外内存的地方,但是对于您正在进行的 10 亿次迭代,这可能是值得的
当你想测量堆中对象的大小时,一个好的方法是使用优秀的工具SizeOf,由于方法,它可以让你获得对象的深度大小SizeOf.deepSizeOf
。
所以这里例如一个 ArrayList
和 只有 1000 万个对象实例(实际上我没有像你的例子那样使用 10 亿)需要 205 Mo
,如果我将大小正确设置为 1000 万(感谢 new ArrayList(size)
),它会将大小减小到 190 Mo
。在 HashSet
的情况下,无论我是否设置大小,它都需要 521 Mo
所以它要大两倍以上。
注意: 我在 64-Bit JVM
启用 UseCompressedOops
的情况下得到了这些结果。
请注意,大小将取决于目标 JVM,如果目标 JVM 是 32-bit JVM
、64-bit JVM
和 UseCompressedOops
(-XX: +UseCompressedOops) 启用,默认情况下堆小于 32 GB
或 64-bit JVM
禁用 UseCompressedOops
(-XX:-UseCompressedOops).
在下面的测试中:
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 消耗更多内存。 答案中损坏的 link 看起来像是 this one.
我的测试有问题吗?或者 ArrayLists 在内存使用方面真的比 HashSet 更差?
--更新:实际上,通过使用 collection.add(".");我从 arrayList 中获取 outOfMemory。但是对于 collection.add(new Object());我两个都买。
哈希集消耗更多内存是有意义的,因为它们需要为潜在的哈希值(桶)设置空间。现在我不知道它是否消耗了 5.5 倍的内存(当然这取决于您存储的对象的性质)但可以这样想。哈希集之于哈希表就像数组列表之于数组一样。您将在哈希集中有一些空白空间,这就是消耗额外内存的地方,但是对于您正在进行的 10 亿次迭代,这可能是值得的
当你想测量堆中对象的大小时,一个好的方法是使用优秀的工具SizeOf,由于方法,它可以让你获得对象的深度大小SizeOf.deepSizeOf
。
所以这里例如一个 ArrayList
和 只有 1000 万个对象实例(实际上我没有像你的例子那样使用 10 亿)需要 205 Mo
,如果我将大小正确设置为 1000 万(感谢 new ArrayList(size)
),它会将大小减小到 190 Mo
。在 HashSet
的情况下,无论我是否设置大小,它都需要 521 Mo
所以它要大两倍以上。
注意: 我在 64-Bit JVM
启用 UseCompressedOops
的情况下得到了这些结果。
请注意,大小将取决于目标 JVM,如果目标 JVM 是 32-bit JVM
、64-bit JVM
和 UseCompressedOops
(-XX: +UseCompressedOops) 启用,默认情况下堆小于 32 GB
或 64-bit JVM
禁用 UseCompressedOops
(-XX:-UseCompressedOops).