Ошибка пространства кучи Java Outofmemory: Как создать деку из вектора? - PullRequest
4 голосов
/ 02 февраля 2010

Я новичок в Java и очень нуждаюсь в вашей помощи.

В настоящее время я использую очередь, поток получателя помещает данные в эту очередь, и анализатор считывает из нее. Но проблема в том, что приемник может получать с невероятной максимальной скоростью, например, . 3000 / сек, в то время как парсер анализирует только на 100 / сек.

РЕДАКТИРОВАТЬ: я проверил, очередь сначала остается на 100 или около того, а после десяти секунд он начинает расти на 100 за во-вторых, и вылетает в 2000 или около того. Возможно ли, что есть утечка памяти?

Мой код (в замкнутом цикле)

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

Куча заполняется слишком быстро, и я получаю исключение вне памяти. Я предполагаю, что проблема в том, что очередь создается с использованием связанного списка, и все указатели должны быть сохранены в куче.

Я знаю версию C, которая делает то же самое (использует буфер), но имеет гораздо лучшую производительность, но из-за проблем развертывания мы можем использовать только Java.

Ответы [ 7 ]

2 голосов
/ 02 февраля 2010

Поскольку данные поступают в 30 раз быстрее, чем обрабатываются, вы можете расширить HeapSize, используя

java -Xms<initial heap size> -Xmx<maximum heap size> если передача завершена до того, как ваша память исчерпана.

  • Или, как вы сами предложили, сбросить данные на диск и обработать их с задержкой.
  • В противном случае вам придется оптимизировать ваш парсер
2 голосов
/ 02 февраля 2010

Если вы получаете 3000 / сек, но обрабатываете только 100 / сек, рано или поздно вам не хватит памяти. Могу ли я предложить вам использовать больше потоков для анализа?

Что касается очереди, посмотрите на LinkedBlockingDeque и LinkedBlockingQueue . Существуют обе высокопроизводительные реализации потоковобезопасных очередей.

1 голос
/ 02 февраля 2010

Полагаю, проблема в том, что очередь создается с использованием связанного списка, и все указатели должны быть сохранены в куче.

Я так не думаю. Я думаю, что проблема real - это несоответствие между скоростью, с которой ваша система получает ввод, и скоростью, с которой она может ее обрабатывать. Если вы не сможете обработать хотя бы среднюю скорость ввода, у вас в конечном итоге не останется памяти, независимо от того, как вы представляете очередь.

Вы должны либо улучшить скорость обработки, либо уменьшить скорость ввода, либо ... отбросить данные.

1 голос
/ 02 февраля 2010

Если производитель производит больше данных, чем может обработать потребитель, тогда данные начнут накапливаться, и в конечном итоге вы столкнетесь с проблемами OutOfMemory. Это будет зависеть от (1) разницы в скорости между производителем и потребителем, (2) количеством данных, которые вы должны обработать.

Я предлагаю вам ограничить количество элементов в очереди. Используйте BlockingDeque -> LinkedBlockingDeque, чтобы ограничить емкость очереди и заблокировать цикл при достижении предела. Таким образом, очередь выполняет функцию кэша для синтаксического анализатора.

0 голосов
/ 31 января 2018

У меня есть теория, реализация ArrayDeque (по крайней мере, в Oracle JDK, я не уверен насчет Android) кажется, никогда не освобождает вытолкнутые элементы.

Другими словами, слоты для вытолкнутых элементов просто обнуляются. В то время как элементы, добавленные к хвосту, будут увеличивать «внутренний массив» на вечность, что рано или поздно вызовет проблемы.

Этот код из Oracle 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).

0 голосов
/ 02 февраля 2010

Когда вы запускаете java, вы можете использовать параметр -Xmx, чтобы сделать больше памяти доступной для виртуальной машины. Например, java -Xmx512m позволит виртуальной машине выделять до 512 МБ памяти. (Значение по умолчанию довольно мало).

Но если вы выделяете память и заполняете список данными, а не удаляете их, в конечном итоге вам не хватит памяти, независимо от того, какой язык вы используете.

0 голосов
/ 02 февраля 2010

Другим способом сделать это будет выборка данных, когда очередь становится слишком большой, и сохранение частоты дискретизации, чтобы мы могли смоделировать исходные данные.

...