Настройка GC для аудио приложения Java

Я заметил, что при воспроизведении аудио в Java этап MarkSweepCompact в gc слишком длинный и приводит к коротким периодам молчания, что недопустимо. Поэтому мне нужно использовать gc с низкой паузой. Я пробовал Parallel и CMS, они, кажется, работают лучше, потому что я полагаю, что пауза короче, и они не выполняют полный сбор так часто, как по умолчанию.

До сих пор я тестировал свою программу со следующими параметрами ParallelGC:

-XX:+UseParallelGC 
-XX:MaxGCPauseMillis=70

и для ConcurrentMarkSweep:

-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing

Я также попробовал G1GC, но он все еще экспериментальный в Java 6. Варианты для обоих режимов:

-Xms15m
-Xmx40m
-XX:+UnlockExperimentalVMOptions
-XX:+CMSClassUnloadingEnabled
-XX:+TieredCompilation
-XX:+AggressiveOpts
-XX:+UseAdaptiveSizePolicy
-Dsun.java2d.noddraw=false
-Dswing.aatext=true
-XX:MaxPermSize=25m
-XX:MaxHeapFreeRatio=10
-XX:MinHeapFreeRatio=10

Какой GC лучше в этой ситуации? Можно ли оптимизировать какие-либо из этих параметров для лучшей производительности процессора и минимального использования памяти?

РЕДАКТИРОВАТЬ Чтобы распознать паузу, которую я записываю, время записи аудиоданных в выходную строку обычно составляет от 92 до 120 мс (я пишу 16384 байта = ~92 мс), объявление при запуске Full GC составляет более 200 мс:

65.424: [Full GC (System) [PSYoungGen: 872K->0K(2432K)] [PSOldGen: 12475K->12905K(16960K)] 13348K->12905K(19392K) [PSPermGen: 15051K->15051K(22272K)], 0.2145081 secs] [Times: user=0.20 sys=0.00, real=0.21 secs] 
Was writing 16384 bytes, time to write 263 ms

Шаблон распределенияEDIT2 для моего приложения следующий: он загружает кучу объектов при запуске, затем начинает играть, и я думаю, большинство объектов после этого выделяются графическим интерфейсом, потому что запуск / приостановка звука не изменяет график GC много. Вот что VisualGC показывает с параллельным GC:альтернативный текст

График начинается при запуске, и я начинаю воспроизведение. Помечены как

1) задержка звука и полный gc, я думаю, это увеличилось Старый размер:

101.646: [Full GC [PSYoungGen: 64K->0K(6848K)] [PSOldGen: 15792K->12773K(19328K)] 15856K->12773K(26176K) [PSPermGen: 15042K->14898K(23808K)], 0.2411479 secs] [Times: user=0.19 sys=0.00, real=0.24 secs]

2) Я открываю окно приложения и приостанавливаю воспроизведение. Ничего особо не меняется, чуть позже это увеличивает размер eden.

3) Я открываю окна и снова начинаю воспроизведение.

Так что мне нужно увеличить выделенный размер Old Gen? Как я могу это сделать? Я бегу с -XX:NewRatio=10 и -XX:NewSize=10m

Спасибо.

4 ответа

Решение

Предоставляемый вами журнал слишком мал, чтобы обеспечить реальный анализ, но в нем говорится, что он потратил 200 мс, делая мало, поскольку старый ген в основном заполнен. Это означает, что ваша куча слишком мала или у вас утечка памяти. Вы не можете ничего сделать для настройки алгоритма GC в этой ситуации. Поэтому остальная часть этого ответа о том, как вы можете получить больше информации из приложения и / или как настроить GC, как только вы устранили утечку памяти или имеете большую кучу.

В значительной степени низкая пауза означает делать все возможное, чтобы коллекции были только молодыми.

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

Вещи, которые я сделал бы немедленно;

  1. измените свое журналирование так, чтобы вы выводили одну строку, легко разбираемую скриптом (возможно, время начала, время окончания, продолжительность)
  2. добавьте переключатели PrintGCApplicationStoppedTime и PrintGCApplicationConcurrentTime, чтобы получить запись каждой паузы STW, а не только событий GC
  3. используйте последнюю версию JVM (т.е. 6u23), так как за последние год-два было много улучшений в горячей точке, поэтому есть смысл использовать более старую
  4. Вы не говорите, если у вас ограниченная память, но я определенно увеличу размер кучи, если вы можете, 40M довольно мало, поэтому у вас не так много места для игры
  5. Запустите приложение с подключенным visualgc, оно дает более полное представление о том, что происходит в IMO, поскольку у вас есть все различные представления одновременно

Главное - определить, где у вас заканчивается пространство и почему. Вероятно, ответ на этот вопрос заключается в том, на что похож шаблон распределения вашего приложения: генерирует ли он нагрузку недолговечных объектов, так что вы действительно быстро прожигаете свой крошечный рай? Является ли порог владения слишком высоким, чтобы вы пинговали объекты через оставшиеся в живых до того, как они все-таки владели, и, таким образом, вынуждали частых владений (медленно)?

Несколько других вещей, которые нужно иметь в виду...

  • iCMS (в инкрементах) предназначался для использования на 1 или 2 основных компьютерах. Описывает ли это вашу машину? сколько ядер у вас есть? Вы можете просто отказаться от этой опции
  • CMS имеет однопоточную фазу (начальная отметка), это может повредить вам
  • CMS обычно предпочитает большую кучу, чем другие сборщики, ваш довольно маленький

Редактирование после визуального графика добавлено в вопрос. Поскольку у вас ограниченная память, вам нужно наилучшим образом использовать имеющееся у вас пространство, единственный способ сделать это - повторить сравнительный анализ... в идеале - с помощью повторяемого теста.

  • ты можешь использовать -Xmn Чтобы указать установленный размер молодого поколения, остаток будет отдан на постоянное проживание.
  • Возможно, вы захотите настроить использование пространств для выживших так, чтобы они были полнее до того, как они поменялись местами, и чтобы объекты жили там дольше, прежде чем они будут владеть землей.
    • -XX:TargetSurvivorRatio=90 устанавливает его таким образом, чтобы пространство для выживших должно было быть заполнено на 90% до того, как оно будет скопировано, очевидно, здесь есть компромисс между стоимостью копирования и использованием пространства
    • использование -XX:+PrintTenuringDistribution чтобы показать размер каждого пространства и как дела, вы также можете увидеть это в VisualGC
    • использование -XX:+MaxTenuringThreshold чтобы указать, сколько раз объект может пережить молодую коллекцию (скопировать из одного пространства выживших в другое) до того, как он будет сохранен, например, если вы знаете, что получаете только недолговечный мусор или вещи, которые живут вечно, разумно установить значение 1
  • Вам необходимо понять, что вызывает постоянные коллекции, и, возможно, стоит подумать о том, чтобы предпринять действия, чтобы они сработали позже.
    • для CMS это может включать в себя настройку -XX:CMSInitiatingOccupancyFraction=<value> Например, установите значение 80, и это приведет к тому, что CMS заполняется на 80% из числа занятых (примечание: это плохая вещь, чтобы ошибаться, поэтому вы можете предпочесть, чтобы точка доступа управляла этим; установите ее слишком маленькой, и она будет собирать слишком часто, убивая производительность, установите его слишком большим, и он может сработать слишком поздно, что приведет к незапланированному полному сбору с соответственно длительным временем паузы
  • если это действительно старые коллекции, которые причиняют вам боль и вам нужна низкая пауза, тогда используйте CMS и ParNew

Наконец, получите профилировщик и выясните, откуда поступает мусор, вы можете обнаружить, что легче контролировать скорость, с которой образуется мусор, а затем направлять усилия в черную дыру, которая может быть GC-настройкой!

Это подразумевает, что слишком много объектов объекты продвигаются из пространства Эдема, так как основной GC не должен иметь дело с большим количеством. С помощью -XX:NewRatio вы можете увеличить соотношение пространства для новых поколений. Попробуйте 10 и двигайтесь вверх.
Более того, исследуйте, как вы можете уменьшить область, в которой объекты в вашей программе остаются ссылками.

Я знаю, что это старый вопрос, и OP, вероятно, даже больше не заинтересован, но меня беспокоит, что эти строки были в его конфигурации:

-XX:MaxHeapFreeRatio=10
-XX:MinHeapFreeRatio=10 

Для меня это означает, что его виртуальная машина попытается ПОСТОЯННО запросить память у системы или освободить ее - я почти уверен, что между этими двумя числами должен быть разрыв.

Кроме того, для тех, кто пытается создать Java-систему в реальном времени, хитрость заключается в том, чтобы выделить ВСЕ ваши объекты заранее, а затем никогда не размещать что-либо еще.

Это может быть непросто, но это не невозможно в долгосрочной перспективе - включите -verbose:gc и просто удалите "New" и другие вещи, которые выделяют память, пока вы вообще не увидите gcs.

Кстати, в графическом интерфейсе это означает предварительное создание всех элементов графического интерфейса и никогда их не освобождает, а просто скрывает и показывает. Это также означает отсутствие манипуляций со строками (используйте только StringBuffers и строковые константы - это самое трудное решение, потому что многие системные вызовы зависят от строк).

Хорошо, короче говоря, у вас есть нефункциональное требование к системе, которое не указано для удовлетворения этого требования. "Правильный" ответ - использовать реализацию JVM с поддержкой реального времени. Но большинство из них дорогие, и я предполагаю, что вы примете правильное решение на 99,9%.

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

После этого вступительного заявления давайте перейдем к вашей проблеме:

Вы сказали, что сборщик мусора вводит паузы в воспроизведение звука. Ваши варианты:

  1. Улучшите сборщик мусора, используя более подходящие опции.
  2. Создайте меньше мусора.
  3. Периодически вызывайте сборщик мусора, но это вполне может привести к обратному эффекту. Вы должны измерить!
  4. Используйте методы сокрытия времени ожидания, чтобы уменьшить влияние пауз, вызванных сборщиком мусора.

Подведение итогов: если вы действительно хотите избавиться от этой проблемы, (1) найдите способ ее измерить, (2) проведите эксперименты, (3) найдите основную причину, (4) устраните основную причину и (5) Измерить, что вы действительно решили это.

Другие вопросы по тегам