2013-08-21 78 views
4

我想在Java中迭代HashMap的值而不創建任何需要垃圾收集的新對象。這是很容易迭代使用增強的for循環值,如:迭代HashMap的值而不創建任何新對象要垃圾收集

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

但是,這將在後臺創建的Iterator對象(我想?)

我想出的最好的是這個代碼:

但老實說,我不知道GC會用這個數組做什麼。

有沒有一種完美的方法來做到這一點,或者有沒有辦法用一個可重用對象來做到這一點?

編輯:這是一個Android遊戲,並且有很多這樣的循環創建對象並影響性能。編輯#2:對於那些懷疑,我重構的只是一部分最常被稱爲增強for循環,主要是ArrayLists,已經對基於jvisualvm堆分析的內存使用產生了重大影響。當然,其中的一部分可能是因爲我有太多的ArrayLists,或者在沒有必要時循環它們。

+0

爲什麼你不想創建一個對象?我認爲創建迭代器的開銷並不值得它創建一個(可能是古怪的)解決方法。但如果有一個很好的理由,我很感興趣聽到它。 :) –

+0

你爲什麼在意?創建一個迭代器並進行垃圾回收非常快。不要優化不需要優化的東西。 –

+0

爲什麼有必要沒有臨時對象? – hexafraction

回答

3

但是,這將在後臺創建的Iterator對象(我想?)

是會的。

我想出的最好的是這樣的代碼:

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

但是說實話,我不知道,GC將這個數組做。

實際上這將是比使用Iterator明確地或隱含更糟:

  • toArray()方法分配一個新的數組和複製值元素集合到它。
  • 致電values()可能實例化一個Set對象。
  • toArray()的內部調用iterator()對值集合對象創建一個新的Iterator實例。

因此,無論如何,您正在分配一個Iterator和一個臨時數組,AND(可能)一個Set對象。


我異形堆和最大的一組對象是ArrayList$Itr(不涉及這個HashMap的例子,但我目前正在重寫所有增強的for循環,以標準循環)

由於你指出,這是一個不同的情況。但我仍然認爲你在這裏咆哮錯誤的樹。如果您使用的是最近的HotSpot JVM,那麼分配和垃圾收集短暫對象(即沒有終身使用的對象)的成本是很小的。除非您有特定的原因來減少對象分配率,否則您的所有工作在實際可衡量的性能改進方面可能會少得多。

+0

感謝您的信息,它爲我清除了一些東西。有一件事是因爲這是一款Android遊戲,它在Dalvik虛擬機上而不是HotSpot。 – talloaktrees

+0

我知道Davlik VM的GC不如Hotspot。但是如果您的應用/遊戲遇到GC暫停,我仍然只會優化迭代器的使用。 –

2

for-each循環是迄今爲止您的最佳選擇:它是高效且可讀的。老實說,你會注意到在避免創建一個迭代器時沒有改變。迭代器專門用於迭代,所以它的效率和優化都是這樣做的。創建數組是最糟糕的選擇:它爲已經處於完美迭代數據結構的對象分配內存。

關於你的編輯:你確定這是因爲迭代器?你真的微觀基準嗎?我很確定在這個循環中還有其他東西,比簡單創建一個非常輕的對象需要更多的時間。嘗試弄清楚是什麼,並在使代碼複雜化之前優化真正重要的內容。

+0

+1。無法同意模式。 –

+0

我描述了堆,最大的一組對象是ArrayList $ Itr(與此HashMap示例無關,但我目前正在將所有增強的for循環重寫爲標準循環) – talloaktrees