迭代HashMap的值而不创建任何新的对象作为Garbage Collected

时间:2013-08-21 07:28:51

标签: java hashmap iteration

我试图在Java中迭代HashMap的值,而不创建任何需要进行垃圾回收的新对象。使用增强的for循环很容易迭代值,如下所示:

for (Value v : myMap.values()) {
    ....
}

但这会在幕后创建一个Iterator对象(我想?)

我提出的最好的是这段代码:

Object[] values = myMap.values.toArray();
...standard "int i" for loop on the array

但说实话,我不确定GC会对这个阵列做些什么。

有没有一种完美的方法可以做到这一点,还是有办法用一个可重复使用的对象来做到这一点?

编辑:这是针对Android游戏的,有很多这样的循环正在创建对象并影响性能。

编辑#2:对于那些怀疑的人,我重构了一部分最常被称为增强型for循环的部分,主要是在ArrayLists上,对基于jvisualvm堆分析的内存使用产生了重大影响。当然,部分原因可能是因为我有太多的ArrayLists,或者当它不是真的必要时循环遍历它们。

2 个答案:

答案 0 :(得分:3)

  

但这会在幕后创建一个Iterator对象(我想?)

是的。

  

我提出的最好的是这段代码:

  Object[] values = myMap.values.toArray();
  ...standard "int i" for loop on the array
     

但说实话,我不确定GC会对这个阵列做些什么。

事实上,这比明确或隐含地使用Iterator更糟糕:

  • toArray()方法分配一个新数组并将值集元素复制到其中。
  • values() 的调用可能会实例化Set个对象。
  • toArray()的调用会在值集对象上内部调用iterator(),从而创建新的Iterator实例。

所以你要分配一个Iterator,一个临时数组,和(可能)一个Set对象。


  

我分析了堆,最大的对象集是ArrayList$Itr(与此HashMap示例无关,但我目前正在将所有增强的for循环重写为标准for循环)

正如您所指出的,这是一个不同的情况。但我仍然认为你在这里咆哮错误的树。如果您使用的是最近的HotSpot JVM,那么分配和垃圾收集短期对象(即那些没有获得终结的对象)的成本非常小。除非您有特定的理由降低对象分配率,否则您的所有工作在实际可衡量的性能改进方面可能收效甚微。

答案 1 :(得分:2)

for-each循环是目前最好的选择:它高效且易读。

老实说,你会发现试图避免创建迭代器没有任何变化。迭代器专门用于迭代,因此它在这方面是高效和优化的。创建数组是最糟糕的选择:它为已经处于完全可迭代数据结构的对象分配内存。

关于你的编辑:你确定是因为迭代器吗?你真的微基准吗?我很确定在循环中还有其他东西比简单创建一个非常轻的对象需要更多的时间。尝试弄清楚那是什么,并在使代码复杂化之前优化真正重要的内容。