2017-01-05 24 views
2

我想知道是否有人能解釋我的代碼出了什麼問題。 我有一個IgniteCache Long-> Object []這是一種批處理機制。使用CacheEntryProcessor和修改緩存條目時出現奇怪的內存使用情況

緩存是onheap,分區並配置了一個備份。

我想修改緩存項值數組中的一些對象。 所以我寫了當集羣裝入數據CacheEntryProcessor

的實施
@Override 
    public Object process(MutableEntry<Long, Object[]> entry, Object... arguments) 
        throws EntryProcessorException { 
     boolean updated = false; 
     int key = (int)arguments[0]; 
     Set<Long> someIds = Ignition.ignite().cluster().nodeLocalMap().get(key); 

     Object[] values = entry.getValue(); 
     for (int i = 0; i < values.length; i++) { 
      Person p = (Person) values[i]; 
      if (someIds.contains(p.getId())) { 
       p.modify(); 
       if (!updated) { 
        updated = true; 
       } 
      } 
     } 
     if (updated) { 
      entry.setValue(values); 
     } 
     return null; 
    } 
} 

每個節點消耗約堆的20GB和。 當我在多節點集羣上運行cache.invokeAll緩存處理器時,我有一個瘋狂的內存行爲 - 當處理器運行時,我看到內存使用量甚至達到48GB或更高,最終導致節點與集羣分離導致GC太長。

但是,如果我刪除entry.setValue(values)行,它將修改後的數組存儲回緩存中一切正常,除了數據不會被複制,因爲緩存不知道更改 - 更新是隻有主節點:(上可見

誰能告訴我怎麼做工作?有什麼不對的這種做法?

回答

0

首先,我不會推薦分配大的堆大小,這將非常可能會導致長時間的GC暫停,即使一切工作正常。基本上,JVM不會清理內存,直到它達到一定的閾值,並且當它到達時,將會有很多垃圾LECT。嘗試切換到堆外或啓動更多Ignite節點。

事實上,如果更新條目時會生成更多垃圾,這是非常有意義的。基本上每次更新時,都會用新的替換舊的值,而舊的則變成垃圾。

如果這些都不起作用,請抓取堆轉儲並檢查佔用內存的內容。

+0

當然,我知道使用大堆時存在的不同問題,但到目前爲止,它對我們來說並沒有什麼大不了的。我們在內存映射減少作業中運行,這些作業爲存儲在緩存中的對象創建了一些統計信息 - 在給定相同硬件設置的情況下,堆上操作比堆外簡單快捷 - 我們始終都會對所有數據進行處理。你能解釋一下entry.setValue是如何工作的嗎?這次通話背後發生了什麼?對我來說,它看起來像必須有一個對象創建或序列化的副本,因爲我注意到對象出現在舊版本中(必須由於它們的大小)。 – Bart

+0

詢問是因爲我正在修改原始數組而不是創建新對象並通過setValue存儲它們。根據setValue的代碼,它將oldVal分配給前一個值,val分配給新的值,所以我想知道新對象來自哪裏。 – Bart

+1

是的,獲取值時會創建副本,並且'setValue'用新值替換舊值。 –