【问题标题】:Memory efficency of clearing a HashSet vs. creating a new HashSet清除 HashSet 与创建新 HashSet 的内存效率
【发布时间】:2013-06-17 19:54:17
【问题描述】:

好奇心和效率是这个问题的原因。我处于某些循环运行后创建许多新 HashSet 的情况:

HashSet 目前在类的顶部声明为这样:

private Set<String> failedTests;

然后在代码的后面,每当我重新运行测试时,我都会创建一个新的 failedTests HashSet:

failedTests = new HashSet<String>(16384);

我会一遍又一遍地执行此操作,具体取决于测试的规模。我希望垃圾收集器能够最有效地处理旧数据。但是,我知道另一种选择是在一开始就创建 HashSet:

private Set<String> failedTests = new HashSet<String>(16384);

然后每次循环清除HashSet。

failedTests.clear();

我的问题是,就开销等而言,哪种方法最有效?我不知道 clear() 函数在里面做什么——它是在做同样的事情,将旧数据发送到垃圾收集器,还是在做一些更有效的事情?另外,我给 HashSet 提供了很大的初始容量缓冲,但是如果测试需要超过 2^14 个元素,.clear() 函数是否会将 HashSet 重新实例化为 16384?

补充一下,我找到了source code to clear() here。所以它至少是最坏情况的 O(n) 操作。

使用 clear 函数,我做了一个测试过程,它在 565 秒内完成。 使用GC处理,506秒测试结束。

但这并不是一个完美的基准,因为还有其他外部因素,例如与计算机和网络文件系统的接口。但是整整一分钟确实感觉很好。有没有人推荐一个可以在线路/方法级别上工作的特定分析系统? (我使用的是 Eclipse Indigo)

【问题讨论】:

  • 你试过基准测试吗?
  • 您对自己创建了 多少 个新集有任何衡量标准吗?你真的测试过你的应用程序的行为吗?这是内存与性能问题的一个例子,通常会导致过早的优化。作为基础,您可以创建一个新的HashSet,让 GC 完成它的工作并进行一些分析,以便在担心之前查看实际时间。毕竟,clear 方法涉及迭代、清空引用并允许 GC 完成他的工作。
  • Fastest way to recreate the ArrayList in a for loop 的可能副本:new 通常比 clear 快。
  • 哈希集是通过测试使用的,我注意到时间上的差异很小,但是您是否推荐一个特定的分析解决方案来为每一行代码/方法调用计时?无论如何我都会在最后发布分析,但是我的程序中还有许多其他因素可能会导致延迟,例如文件读取...

标签: java collections garbage-collection


【解决方案1】:

我不知道 clear() 函数在里面做什么

它正在调用它在内部使用的HashMap 表的clear() 方法。在HashMap 中,clear() 方法定义如下:

public void clear() {
  modCount++;
  Entry[] tab = table;
  for (int i = 0; i < tab.length; i++)
      tab[i] = null;
  size = 0;
}

是不是也在做同样的事情,将旧数据发送到垃圾箱 收集,还是做一些更有效的事情?

tab[i] = null 指出它使旧数据符合垃圾回收条件。

另外,我给了 HashSet 一个很大的初始容量缓冲,但是 如果测试需要超过 2^14 个元素,.clear() 函数 将 HashSet 重新实例化为 16384?

不,不会的。

就开销而言,这是最有效的方法, 等等?

我想,Java 垃圾收集器知道如何以最有效的方式完成其工作。所以让垃圾收集器来处理这个问题。所以,我宁愿在每次需要时都创建一个新的 failedTests HashSet

【讨论】:

  • 大对象直接进入永久空间,因此在 Nursery 代中对它们进行 GC 比对较小对象进行 GC 更昂贵。尽管如此,与遍历支持数组的所有 16000 个元素的成本相比,这个成本还是相形见绌。
【解决方案2】:

重新创建 HashSet 效率更高。

1) 如果 HashSet 容量增长到 16384 以上,则清除不会将其重置为初始容量

2) new HashSet(16384) 创建一个新的Entry[16384] 数组,这是一个操作,它比像clear那样一个一个地清空元素更有效

for (int i = 0; i < table.length; i++)
    tab[i] = null;

【讨论】:

    猜你喜欢
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2011-07-02
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    相关资源
    最近更新 更多