2010-02-02 45 views
4

我是新來的Java,真的需要你的幫助。Java Outofmemory堆空間錯誤:如何從矢量中創建雙端隊列?

我目前正在使用一個隊列,一個接收線程將數據放入這個隊列,解析器讀出這個。 但問題是接收器可能以令人難以置信的峯值速度接收,如例如。 3000 /秒,而解析器僅以100 /秒解析。

EDIT:I have checked, the queue first stays at 100 or so, and after ten seconds it starts to grow at 100 per second, and crashes at 2000 or so. Could it be possible that there is a memory leak?

我的代碼(在一個緊密的循環)是

byte[] data = new byte[1024]; 
System.arraycopy(udpPacket.getData(), 0, data, 0, 1024); 
queue.offer(data); 

堆太快填滿,我得到一個內存不足的異常。我想問題是隊列是使用鏈表創建的,所有指針必須保存在堆中。

我知道一個C版本可以做同樣的事情(使用緩衝區),但性能要好得多,但由於部署問題,我們只能使用Java。

+1

既然討論正在進行中,您可以指定接收哪些大寫金額的數據或流TCP或UDP和最新是否傳輸的頻率。這些信息對建議最佳實踐是必要的。 – stacker 2010-02-02 12:35:29

+1

看起來您正在進行大量複製。您可能想要包裝您的數據作爲輸入流並傳遞。 – 2010-02-02 16:45:01

+0

@stacker:我無法控制輸入,我只能控制偵聽器的採樣。 @Nick:是的,我正在做很多複製,而且我不理解將數據封裝爲輸入流。你能解釋一下如何以及爲什麼輸入流更好? – TiansHUo 2010-02-03 02:04:12

回答

2

如果您收到3000 /秒,但只處理100 /秒遲早你將用完內存。 我可以建議你使用更多線程來解析嗎?

關於隊列,看看LinkedBlockingDequeLinkedBlockingQueue。有兩個高性能的線程安全隊列實現。

+0

感謝您的快速回答,但一個愚蠢的問題,我如何解析一個隊列使用多個線程,我不明白。 另一個問題是,我在幾秒鐘內耗盡內存,這是完全不可接受的... – TiansHUo 2010-02-02 11:29:10

+1

我認爲這個idrosid意味着你需要分離從項目處理中刪除隊列中的項目的操作。因此,您從隊列中讀取項目並將其傳遞給多個不同線程中的一個來執行解析。它允許您一次處理多個隊列項目。話雖如此,我認爲它仍然會推遲發生問題而不是消除問題的觀點。 – DaveH 2010-02-02 12:23:56

+0

爲什麼推遲這個問題而不是消除它? – TiansHUo 2010-02-03 02:07:54

0

另一種方法是在隊列變得太大時對數據進行採樣,並保存採樣率以便模擬原始數據。

2

由於數據來自於30倍,比它被處理,你可以使用

java -Xms<initial heap size> -Xmx<maximum heap size>,如果你之前內存耗盡傳輸結束延長HEAPSIZE更快。

  • 或者如您自己建議的將數據轉儲到光盤並延遲處理。
  • 否則,你將不得不您進而優化解析器
+0

是的,優化解析器,這是一個好主意,因爲當峯值發生時,數據通常是同質的,所以也許我可以保留頂部數據的統計和做一些聚合 – TiansHUo 2010-02-02 11:35:19

+0

@TiansHUo,這不是答案。它可能現在解決你的問題,但是當將來需要處理更多的數據時,你可能會遇到更多的問題... – 2010-02-02 11:38:54

+0

呵呵?你能否澄清當需要處理更多數據時會出現什麼問題。或者你可以指導如何改進算法... – TiansHUo 2010-02-02 11:51:29

0

當您運行java,您可以使用-Xmx參數,使更多的可用內存的虛擬機。例如,java -Xmx512m將允許VM分配高達512Mb的內存。 (默認值相當小)。

但是,如果您要分配內存並填充數據列表並永不刪除它,那麼無論您使用的是哪種語言,最終都會導致內存不足。

1

如果生產者生產更多的數據然後消費者可以處理,那麼數據將開始積累,最終你會遇到OutOfMemory問題。這取決於(1)生產者和消費者之間的差異,(2)你必須處理的數據量。

我建議你限制隊列中物品的數量。使用BlockingDeque - >LinkedBlockingDeque來限制隊列的容量,並在達到限制時阻止您的循環。這樣,隊列就像解析器的緩存一樣。

+0

但現在的問題是,隊列只有2000左右,我得到了一個outofmemory異常,我想有一個內存泄漏 – TiansHUo 2010-02-02 11:55:23

+0

Humm,這真的是少量的數據...從我的計算1.9MB ..應該不成問題。 – 2010-02-02 12:13:52

+0

是否有任何(最好是開源)工具可以建議幫助我查看真正的問題在哪裏? – TiansHUo 2010-02-03 02:06:44

1

I guess the problem is that queue is made using a linked-list, and all the pointers must be saved in the heap.

我不這麼認爲。我認爲真正的問題是您的系統獲取輸入的速率與其可以處理的速率之間的不匹配。除非您可以至少以平均輸入速率進行處理,否則無論您如何表示隊列,最終都會耗盡內存。

您必須提高處理速度,降低輸入速率或降低數據。

0

我有一個理論,ArrayDeque實現(至少在甲骨文的JDK,我不知道關於Android的)似乎來從來沒有真正解除分配彈出元素。

換句話說,用於彈出元素的插槽僅僅是零。雖然添加到尾巴的元素將使「內陣」在永恆中變得更大,這遲早會造成麻煩。

此代碼從JDK甲骨文1.8.0_144:

public E pollFirst() { 
    int h = head; 
    @SuppressWarnings("unchecked") 
    E result = (E) elements[h]; 
    // Element is null if deque empty 
    if (result == null) 
     return null; 
    elements[h] = null;  // Must null out slot 
    head = (h + 1) & (elements.length - 1); 
    return result; 
} 

法術找我的麻煩。 :(

如果我的分析是真實的,似乎是ArrayDeque從未打算成爲一個「真正的」 FIFO隊列,並且是不適合這樣的目的。(不幸的是我目前需要這樣的目的現在)

我目前正在調查LinkedList而不是(這也實現了Deque)。