我在我的應用程序中有一個散列表。該地圖處於單身狀態,並且使用同步方法保護對更新或讀取的訪問權限。散列表放置性能問題
當使用大量(20000+)併發線程進行測試時,會出現我的問題。當線程正在使用put()即時獲取OutOfMemory異常寫入映射。
讀取操作很好(我可以模擬100多個線程),沒有任何問題。
任何關於如何使我的hashmap更高性能寫入的建議?這也可能是我在存儲器中存儲這麼多數據的方法的限制嗎?
我在我的應用程序中有一個散列表。該地圖處於單身狀態,並且使用同步方法保護對更新或讀取的訪問權限。散列表放置性能問題
當使用大量(20000+)併發線程進行測試時,會出現我的問題。當線程正在使用put()即時獲取OutOfMemory異常寫入映射。
讀取操作很好(我可以模擬100多個線程),沒有任何問題。
任何關於如何使我的hashmap更高性能寫入的建議?這也可能是我在存儲器中存儲這麼多數據的方法的限制嗎?
由於線程數量的限制,我懷疑您的PermGen內存不足。你的OutOfMemoryError
異常應該告訴你它是堆還是PermGen。
Java中的每個線程都使用大約256-512千字節的堆棧,它是從PermGen分配的。因此,超過默認PermGen大小(通常爲64-256 MB)的20,000個線程* 256 KB = 5 GB。
您應該將線程數限制在少於幾百個。看看Java 5/6的併發包,特別是ThreadPoolExecutor。
感謝您提供良好的信息,我如何查看它是否出於PermGen?當拋出OOM異常時,它只會給出一個下面的異常「OutOfMemoryError:無法創建新的本地線程」以及堆棧跟蹤。當我使用探查器時,生成的日誌顯示異常拋出「java.lang.OutOfMemoryError:請求160008字節的Chunk :: new。Out of swap space?」。在這個日誌中,perm gen-total = 11288k,used = 4498k。我認爲使用探查器導致不同的內存使用情況,所以我不能相信它。我嘗試使用-XX:HeapDumpPath arg在OOM發生時創建堆轉儲,但不是。 – cduggan 2011-05-01 09:34:36
如果讀取操作允許100000個線程,那麼這是一個PermGen問題? – cduggan 2011-05-01 11:55:26
'無法創建新的本地線程',所以它出現了Java,無論出於何種原因,都無法創建新的線程。所以看起來你有太多的線程。 – 2011-05-01 15:22:42
如果您使用JDK1.5 +,ConcurrentHashMap是一個不錯的選擇。這很有效。
參見:What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map)?
另外,我覺得put()
可能會導致新的存儲器中的地圖和更費時分配,但不get()
。所以更多的線程將被阻止在put()
。
此外,優化您的關鍵類的hashCode()
方法。這很重要,因爲散列碼計算在您的案例中是密集型操作。如果密鑰對象是不可變的,則只需計算一次散列代碼並將其保存爲成員並直接在hashCode()
中返回。
OutOfMemoryError可能是由大量的對象存儲而不是大量的線程引起的,而OOME不是性能問題。
順便說一句,您可以使用ConcurrentHashMap進行快速併發讀取和寫入,並且不使用一個全局鎖。
你試過了一個ConcurrentHashMap嗎?在正確的編碼環境下,您不需要任何同步。內部有多個分條鎖以減少爭用,以及許多好的複合原子操作,如putIfAbsent,可能允許您完全刪除外部鎖。
至於內存,我懷疑你真的在JVM中存儲了很多。使用像visualvm這樣的監視工具來檢查它,或者爲JVM分配添加更多的內存。考慮像EHCache這樣的緩存,它會自動溢出到磁盤,並在內部使用ConcurrentHashMap,並有各種不同的邊界選項
歡呼,與visualvm我可以確定它確定太多的線程。 – cduggan 2011-05-03 18:37:14
聽起來像你的問題是內存,而不是性能。
嘗試使用相同的哈希碼將最近最少訪問的鍵和值寫入文件 ,並從內存中清除它們。
如果存儲哈希碼的文件被尋址,則將最近使用的哈希碼的密鑰和銷售額寫入文件並從存儲器中清除,然後將期望存儲的讀取文件讀取到存儲器。
考慮多層次的hashmaps(每個都有不同的鍵)以提高性能。
如果您想保留當前的實現,您可能還需要考慮通過更改傳遞給Java的-Xms和-Xmx參數來更改分配給應用程序的內存量。還有許多其他參數。無論使用何種實現,都可能需要這樣做。
至於你的問題的最後一部分:
如何,我可以讓我的HashMap的寫入性能更高的任何建議?這也可能是我在存儲器中存儲這麼多數據的方法的限制嗎?
我使用了一個工具來看看應用程序在做什麼。它可以做堆和線程轉儲。它還有一個顯示cpu,類加載,線程,堆和perm gen的montior。它被稱爲Java VisualVM,它是jdk 1.6的一部分.exe位於jdk的bin文件夾中。我將使用它來跟蹤我們代碼中的一些線程問題。
HTH, James
使用數據庫,也許? – 2011-04-30 23:22:36
是的,像這樣的一大組數據應該(部分)存儲在磁盤備份的散列映射中,這是一個數據庫。 – 2011-04-30 23:45:28
數據庫不是這個特定應用 – cduggan 2011-05-01 11:54:11