2010-02-02 44 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)。