2012-12-15 50 views
3

我在Java中有一個非常奇怪的GC問題。我跑個下面這段代碼:舊的堆空間溢出

while(some condition){ 
     //do a lot of work... 
     logger.info("Generating resulting time series..."); 
     Collection<MetricTimeSeries> allSeries = manager.getTimeSeries(); 
     logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size())); 

     //for (MetricTimeSeries series : allSeries) { 
      // just empty loop 
     //} 
} 

當我看着JConsole的,在每次循環的重新啓動,我的老根堆空間,如果我手動強制GC,需要一個大小約爲90 MB。如果我取消註釋循環,像這樣

while(some condition){ 
     //do a lot of work... 
     logger.info("Generating resulting time series..."); 
     Collection<MetricTimeSeries> allSeries = manager.getTimeSeries(); 
     logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size())); 

     for (MetricTimeSeries series : allSeries) { 
      // just empty loop 
     } 
} 

即使我強制它刷新,它也不會低於550MB。根據yourKit分析器,可以通過主線程的本地var(集合)訪問TimeSeries對象,緊接着GC重新啓動一個新的迭代之後...而集合是巨大的(250K時間序列)。Wyy是發生這種情況,我該如何「對抗」這種(不正確的?)行爲?

+0

什麼是manager.getTimeSeries();做?另外,它的返回值迭代器函數是做什麼的? –

+0

Itis構建了它所知道的所有時間序列的ArrayList(對於它們管理的所有時間序列,都有底層對象進行相同操作)。最後,一個大的ArrayList被構建並返回,並且迭代器只是標準java迭代器,用於列表 – Bober02

+0

它是否在(某些條件)時退出? p.s.它真正的困難,試圖解決一個問題,這是一個黑盒子 – bluesman

回答

1

由於您正在構建時間系列(大)ArrayList,只要它被引用,就會佔用堆,如果它保持足夠長的時間(如果年輕一代太小,實際上持有它)。我不知道如何將您在JConsole或Yourkit中看到的信息與程序中的特定點相關聯,但是直到通過幾次JIT通過優化空循環後,您的循環將花費更長的時間並保留集合時間更長,這可能解釋了感知的差異,而實際上並不是很多。

沒有什麼不正確的行爲。如果你不想消耗太多內存,你需要改變你的Collection,所以它不是一個熱切填充的ArrayList,而是一個懶惰的集合,更多的流(如果你曾經做過XML處理,那麼認爲DOM vs SAX )在迭代時得到評估。如果你不需要對整個集合進行排序,那是可行的,尤其是因爲你似乎在說集合是由基礎對象返回的子集合的連接。

如果你可以改變你的返回類型從CollectionIterable,例如,你可以使用GuavaFluentIterable.transformAndConcat()到底層對象的集合轉變爲惰性計算Iterable串聯的時間序列。當然,集合的大小不再是直接可用的(並且如果您嘗試獨立於迭代獲取它,則會兩次評估懶惰集合)。

2

是啊,垃圾收集器可以是神祕的..但它打敗了管理自己的記憶;)

Collection和Map有掛到更長的引用威力喜歡比你的方式,從而防止垃圾收集時你可能會期望。正如你注意到的那樣,設置allSeriesnull的引用本身會將它標記爲垃圾收集,因此它的內容也適用於抓取。另一種方法是撥打allSeries.clear():這將取消鏈接所有的MetricTimeSeries對象,並且它們可以免費進行垃圾回收。

爲什麼取消循環還解決了這個問題呢?這是一個更有趣的問題。我試圖建議編譯器正在優化參考allSeries ..但你仍然呼籲allSeries.size()所以它不能完全優化出的參考。

泥濘的水域,不同的編譯(和設置)行爲不同,並使用不同的垃圾收集器,它們本身的行爲有所不同。沒有更多信息,很難準確地說出發生了什麼。

+0

將集合傳遞給其他方法進行處理也有訣竅.... WTF ???? – Bober02

+0

btw,代入常規迭代器,並調用iterator.remove,不會改變 – Bober02