Настройка GC для аудио приложения Java - PullRequest
6 голосов
/ 21 января 2011

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

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

-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 Шаблон размещения для моего приложения следующий: он загружает кучу объектов при запуске, затем начинает играть, и я предполагаю, что большинство объектов после этого выделяются графическим интерфейсом, потому что просмотр / приостановка звук не сильно меняет график ГХ. Вот что 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) Я открываю окна и снова начинаю воспроизведение.

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

Спасибо.

Ответы [ 4 ]

5 голосов
/ 22 января 2011

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

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

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

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

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

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

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

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

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

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

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

3 голосов
/ 21 января 2011

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

1 голос
/ 06 сентября 2012

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

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

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

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

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

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

1 голос
/ 21 января 2011

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...