Вызовите явное удаление объекта Java

Я работаю над сервером Java, который обрабатывает БОЛЬШОЙ очень плотный трафик. Сервер принимает пакеты от клиентов (часто много мегабайтов) и вперед их другим клиентам. Сервер никогда явно хранит любое поступление/исходящие пакеты. Все же сервер постоянно сталкивается OutOfMemoryException исключения.

Я добавил System.gc() в компонент передачи сообщений сервера, надеясь, что память была бы освобождена. Кроме того, я установил размер "кучи" JVM к гигабайту. Я все еще добираюсь так же, как много исключений.

Таким образом, мой вопрос - это: как я могу удостовериться, что сообщения мегабайта не ставятся в очередь неограниченно долго (несмотря на то, чтобы не быть необходимым)? Существует ли способ для меня звонить, "удаляют" на этих объектах гарантировать, что они не используют мое пространство "кучи"?

        try
        {
           while (true)
            {
               int r = generator.nextInt(100);//generate a random number between 0 and 100
                Object o =readFromServer.readObject();
                sum++;
                // if the random number is larger than the drop rate, send the object to client, else
                //it will be dropped
                if (r > dropRate)
                {
                    writeToClient.writeObject(o);
                    writeToClient.flush();
                    numOfSend++;
                    System.out.printf("No. %d send\n",sum);
                }//if

            }//while
        }//try
14
задан Curious George 1 February 2010 в 16:26
поделиться

14 ответов

, глядя на ваш код: ваши objectInput / newsstream экземпляры, вновь созданные каждый раз, когда пакет прибывает или отправляется, и если это так, они правильно закрыты? Если нет, вы звоните Сброс () после каждого чтения / записи? Классы по потоковым объектам хранят ссылку на все, которые они видели (в целях, чтобы избежать повторного пересечения одного и того же объекта каждый раз, когда он передается), предотвращая их быть собранным мусором. У меня была эта точная проблема около 10 лет назад - на самом деле первый раз, когда я должен был использовать профилировщик, чтобы диагностировать утечку памяти ...

3
ответ дан 1 December 2019 в 06:28
поделиться

System.gc () - это только рекомендация для виртуальной машины Java. Вы называете это, и JVM может или не может запустить сборку мусора.

OutofMemoryException может быть вызвано двумя вещами. Либо вы держите (нежелательные) ссылки на ваши объекты, либо вы принимаете на многие пакеты.

Первый случай можно проанализировать профилировщик, где вы пытаетесь узнать, сколько ссылок до сих пор живут. Хорошая индикация для порека памяти растут расход памяти вашего сервера. Если каждый дополнительный запрос делает ваш процесс Java немного расти, шансов вы ведете ли вы ведете какие-то ссылки (JConsole может быть хорошим началом)

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

4
ответ дан 1 December 2019 в 06:28
поделиться

Вы можете TUNE Коллекция мусора в Java, но вы не можете заставить.

2
ответ дан 1 December 2019 в 06:28
поделиться

Вам нужно найти Если вы держите на объекты дольше, чем необходимо. Первый шаг будет получать профилировщик в случае и посмотреть на кучу и понять, почему объекты не собираются.

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

Некоторая полезная информация о настройке GC: http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html

1
ответ дан 1 December 2019 в 06:28
поделиться
[11336681-

Если ваш сервер работает как минимум за несколько минут до того, как он умирает, вы можете попробовать запускать его в Visual VM. Вы можете по крайней мере получить лучшее представление о том, как быстро растет куча, и какие объекты в нем.

0
ответ дан 1 December 2019 в 06:28
поделиться

Сервер принимает пакеты от клиентов (часто много мегабайт) и пересылает их другим клиентам.

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

Возможно, что у вас также есть утечка памяти, но если вышеизложенное верно, то эта конструкция "хранить и пересылать" - ваша самая большая проблема. Вы, вероятно, можете сократить использование памяти на 95%, если перепроектируете приложение так, чтобы оно не получало пакеты полностью, а передавало их непосредственно клиентам, т.е. читало только небольшую часть пакета за раз и немедленно передавало клиентам. Нетрудно сделать это таким образом, чтобы для клиентов это выглядело точно так же, как при хранении и пересылке.

1
ответ дан 1 December 2019 в 06:28
поделиться

Вручную запуск System.gc не является хорошим ответом, так как другие размещены здесь. Он не гарантируется запустить, и он вызывает полный GC, который, вероятно, повесит ваш сервер в течение длительного времени, пока он работает (> 1 сек, если вы даете свой сервер GB RAM, я видел несколько минут Длинные паузы на больших системах). Вы можете настроить свой GC, который, безусловно, поможет, но не полностью исправить проблему.

Если вы читаете объекты из одного потока, а затем пишу их в другой, то есть точка, в которой вы держите весь объект в памяти. Если эти объекты, как вы указываете, большие, то это может быть ваша проблема. Попробуйте переписать свой IO, чтобы вы читали байты от 1 поток и напишите их другому, не так явно держите полный объект (хотя я не вижу, как это будет работать с сериализацией / дезерриализацией объекта, если вам нужно проверить / подтвердить объекты ).

0
ответ дан 1 December 2019 в 06:28
поделиться

просто добавить ко всем предыдущим ответам : System.gc() - это не команда для JVM, чтобы инициировать сбор мусора... это кроткое направление и не гарантирует, что что-то случится. Спецификация JVM оставляет за поставщиками право принимать вызовы о том, что должно быть сделано на вызовах gc. Продавцы могут даже ничего не делать вообще!

0
ответ дан 1 December 2019 в 06:28
поделиться

Наткнулся на этот старый вопрос во время поиска чего-то другого. Я замечаю, что вы так и не получили полного ответа.

Способ решить эту проблему - начать с написания спецификации для функции, которую вы пытаетесь записать.

Спецификация: Хорошо сформированное двоичное дерево считается «сбалансированным по высоте», если (1) оно пустое, или (2) его левый и правый потомки сбалансированы по высоте, и высота левого дерева находится в пределах 1 от высоты правого дерева.

Теперь, когда у вас есть спецификация, код является тривиальным для записи. Просто следуйте спецификации:

IsHeightBalanced(tree)
    return (tree is empty) or 
           (IsHeightBalanced(tree.left) and
            IsHeightBalanced(tree.right) and
            abs(Height(tree.left) - Height(tree.right)) <= 1)

Перевод этого на выбранный вами язык программирования должен быть тривиальным.

Бонусное упражнение : этот наивный набросок кода слишком много раз пересекает дерево при вычислении высоты. Можете ли вы сделать его более эффективным?

Супер бонусное упражнение : предположим, дерево массово несбалансировано. Например, миллион узлов глубоко с одной стороны и три глубоко с другой. Есть ли сценарий, в котором этот алгоритм сдувает стек? Можете ли вы исправить реализацию так, чтобы она никогда не сдувала стек, даже когда дано массово несбалансированное дерево?

UPDATE : Donal Fellows точек в своем ответе, что есть разные определения «сбалансированных», которые можно выбрать. Например, можно принять более строгое определение «сбалансированной высоты» и потребовать, чтобы длина пути к ближайшему пустому потомку находилась в пределах одного из путей к самому удаленному пустому потомку. Мое определение менее строгое, чем это, и поэтому допускает больше деревьев.

Можно также быть менее строгим, чем мое определение; можно было бы сказать, что сбалансированное дерево - это дерево, в котором максимальная длина пути к пустому дереву на каждой ветви отличается не более чем на две, или на три, или на какую-то другую константу. Или максимальная длина пути составляет часть минимальной длины пути, например, половину или четверть.

Это действительно не имеет значения обычно. Точка любого алгоритма балансировки дерева состоит в том, чтобы гарантировать, что вы не окажетесь в ситуации, когда у вас есть миллион узлов с одной стороны и три с другой. Определение Донала прекрасно в теории, но на практике это боль, возникающая при использовании алгоритма балансировки деревьев, который соответствует этому уровню строгости. Экономия на производительности обычно не оправдывает затрат на внедрение. Вы тратите много времени на ненужные перестановки деревьев, чтобы достичь такого уровня равновесия, который на практике не имеет большого значения. Кого волнует, если иногда требуется сорок ветвей, чтобы добраться до самого дальнего листа в миллионном узле несовершенно сбалансированного дерева, когда теоретически оно может занять всего двадцать в идеально сбалансированном дереве? Дело в том, что на это никогда не уходит миллион. Получить от худшего случая миллион вниз до худшего случая сорок, как правило, достаточно хорошо; вы не должны идти все пути к оптимальному делу.

-121--702550-

Вы говорите, что вам явно нужен весь полученный пакет, прежде чем вы сможете отправить его? Что ж,это не значит, что вы должны хранить все это в памяти, не так ли? Возможно ли изменение архитектуры, чтобы сохранить полученные пакеты во внешнем хранилище (возможно, ram-disk или DB, если даже SSD слишком медленный) и затем направить их непосредственно получателю, не загружая их полностью в память?

0
ответ дан 1 December 2019 в 06:28
поделиться

Если вы получаете исключения OutOfMemory, очевидно, что-то все еще содержит ссылку на эти объекты. Вы можете использовать такой инструмент, как jhat , чтобы узнать, где находятся эти ссылки.

1
ответ дан 1 December 2019 в 06:28
поделиться

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

Как насчет использования (небольших, ограниченных) очереди для сообщений для обработки, то вторичная очередь Softreference, которая питается первой очередью? Таким образом, вы гарантируете, что обработка будет продолжаться, но и, что вы не выйдете из ошибок памяти, если сообщения слишком велики (эталонная очередь будет сброшена в этом случае).

2
ответ дан 1 December 2019 в 06:28
поделиться

Вы не можете называть сбор мусора явным. Но проблема не в этом. Возможно, вы храните ссылки на эти сообщения. Отследите, где они обрабатываются, и убедитесь, что ни один объект не содержит ссылок на них после их использования.

Чтобы лучше понять, что такое лучшие практики, прочтите Эффективная Java, глава 2 - это о "Создании и уничтожении объектов"

.
3
ответ дан 1 December 2019 в 06:28
поделиться

Если у вас есть индекс SomenumberFiflefield , то это утверждение будет либо просто разбито на два сканирования диапазона в индексе или обрабатывается как сканирование таблицы / сканирование индекса фильтр.

Последнее более вероятно, при условии, что большинство ваших строк имеют somenumberfield = 999999

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

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

-121--4435185-

Когда JVM находится на краю outofmemoryError , он будет работать .

Так что звонит System.gc () Самостоятельно, не собираюсь решить проблему. Проблема должна быть исправлена ​​где-то еще. Существуют в основном два способа:

  1. написать эффективный код памяти и / или исправить утечки памяти в вашем коде.
  2. Дайте JVM больше памяти.

Использование java Profiler может дать много информации о использовании памяти и потенциальной утечки памяти.

Обновление : Согласно вашему редактированию с дополнительной информацией о коде, вызывающем эту проблему, посмотрите на Ответ Джеффа Ридзи в этой теме , который предлагает использовать objectInputStream # ReadUnshared () и ObjectOutputStream # TrueUnshared () вместо этого. (Связанные) Javadocs также объясняет это довольно хорошо.

11
ответ дан 1 December 2019 в 06:28
поделиться

Объектные потоки содержат ссылки на каждый записанный/читаемый из них объект. Это связано с тем, что протокол сериализации допускает обратные ссылки на объекты, которые появились ранее в потоке. Возможно, вы все же сможете использовать эту конструкцию, но вместо writeObject/readObject используйте writeUnshared/readUnshared. Я думаю, но не уверен, что это помешает потокам сохранять ссылки на объект.

Как говорит Коуэн, метод reset() также используется здесь. Самое безопасное, что можно сделать, это, вероятно, использовать writeUnshared сразу после reset() при записи на ваш ObjectOutputStreams

.
19
ответ дан 1 December 2019 в 06:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: