Настройка звукового приложения 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 лучше в этой ситуации? Может ли любой из этих параметров быть оптимизирован для лучшей производительности процессора и минимального использования памяти?

EDIT Чтобы распознать паузу, я записываю время для записи аудиоданных на выходную строку, обычно от 92 до 120 мс (я пишу 16384 байта = ~ 92 мс), объявление, когда Full GC, 200+ ms:

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 Шаблон распределения для моего приложения следующий: он загружает кучу объектов при запуске, затем начинает воспроизведение, и я думаю, что большинство объектов после этого выделяются gui, поскольку просмотр/приостановка звука не очень сильно меняет график GC. Это то, что visualgc показывает с параллельным gc: alt text

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

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) Я открываю окна и снова запускаю воспроизведение.

Итак, мне нужно увеличить размер старого генерала? Как мне это сделать? Я работаю с -XX: NewRatio = 10 и -XX: NewSize = 10m

Спасибо.

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

После этого вводящего предложения, давайте приходим к вашей проблеме:

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

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

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

Ответ 4

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

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

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

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

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

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