Профилирование Java, настройка производительности и профилирование памяти упражнения

Я о проводить профилирование в мастерской, настройку производительности, профилирование памяти, обнаружение утечек памяти и т. д. Java-приложений с использованием JProfiler и Eclipse Tptp. Мне нужен комплекс упражнений, которые я мог бы предложить участникам, где они могут: Используйте инструмент, чтобы профилировать обнаружение проблемы: узкое место, утечка памяти, неоптимальный код и т. Д. Я уверен, что вокруг достаточно опыта и реальных примеров.

  • Решите проблему и внедрите оптимизированный код
  • Демонстрируйте решение выполняя другой сеанс профилирования
  • В идеале, напишите модульный тест, который демонстрирует увеличение производительности

Проблемы и решения не должны быть чрезмерно сложными; их можно решить в считанные минуты, в лучшем случае - в считанные часы. Некоторые интересные области для упражнений:

  • Устранение утечек памяти
  • Оптимизация циклов
  • Оптимизация создания объектов и управления ими
  • Оптимизация строковых операций
  • Устранение проблем, усугубляемых узкими местами параллелизма и параллелизма

В идеале упражнения должны включать образец неоптимизированного кода и код решения.

15
задан Dan 6 August 2010 в 17:49
поделиться

3 ответа

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

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

Циклы:

  • Вы хотите проверить, не всплывает ли какой-либо набор слов на страницах. Используйте вашу функцию в цикле, но с тем же значением, псевдокод:

     for (word: words) {
    checkWord (скачать (url))
    }
    

    Одно из решений довольно простое: просто загрузите страницу до цикла. Другое решение ниже.

Утечка памяти:

  • простой: вы также можете решить вашу проблему с помощью своего рода кеша. В простейшем случае вы можете просто поместить результаты на (статическую) карту. Но если этого не предотвратить, его размер будет бесконечно расти -> утечка памяти.
    Возможное решение: использовать карту LRU. Скорее всего, производительность не сильно упадет, но утечка памяти должна исчезнуть.
  • более сложный: скажем, вы реализуете предыдущий кеш с помощью WeakHashMap , где ключи - это URL-адреса (НЕ в виде строк, см. Ниже), значения - это экземпляры класса, который содержит URL, загруженный страница и еще кое-что. Вы можете предположить, что все должно быть в порядке, но на самом деле это не так: поскольку значение (которое не имеет слабой ссылки) имеет ссылку на ключ (URL-адрес), ключ никогда не сможет очистить -> хорошая утечка памяти .
    Решение: удалите URL из значения.
  • То же, что и раньше, но URL-адреса являются интернированными строками («для экономии памяти, если у нас снова будут те же строки»), значение не относится к этому. Я не пробовал, но мне кажется, что это тоже вызовет утечку, потому что интернированные строки не могут быть объединены в сборку мусора.
    Решение: не стажироваться, это также приведет к совету, который вы не должны пропускать: не делайте преждевременной оптимизации, поскольку это корень всего зла .

Создание объекта и строки:

  • говорят, что вы хотите отображать только текст страниц (~ удалить теги html). Напишите функцию, которая делает это построчно и добавляет к растущему результату. Сначала результатом должна быть строка, поэтому добавление займет много времени и размещения объекта. Вы можете обнаружить эту проблему с точки зрения производительности (почему добавления такие медленные) и с точки зрения создания объектов (почему мы создали так много строк, буферов String, массивов и т. Д.).
    Решение: используйте StringBuilder для получения результата.

Параллелизм:

  • Вы хотите ускорить весь процесс, выполняя загрузку / фильтрацию параллельно. Создайте несколько потоков и запустите свой код, используя их, но все делайте внутри большого синхронизированного блока (на основе кеша), просто «чтобы защитить кеш от проблем параллелизма». Эффект должен заключаться в том, что вы эффективно используете только один поток, поскольку все остальные ждут блокировки кеша.
    Решение: синхронизируйте только операции с кешем (например, используйте `java.util.collections.synchronizedMap ())

  • Синхронизируйте все крошечные кусочки кода. Это должно убить производительность и, возможно, помешать нормальному параллельному выполнению. Если вам повезет / вы достаточно умны, вы также можете придумать тупиковый замок. Мораль этого: синхронизация должна быть не спонтанной, «не повредит», а хорошо продуманной вещью.

Дополнительное упражнение:

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

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

Не игнорируйте этот метод , потому что он очень хорошо работает для любого языка и ОС по этим причинам . Пример здесь . Также попробуйте использовать примеры с вводом-выводом и значительной глубиной вызова. Не используйте только маленькие программы с привязкой к процессору, такие как Мандельброт. Если вы возьмете этот пример C, который не слишком велик, и перекодируете его на Java, это должно проиллюстрировать большинство ваших соображений.

Посмотрим:

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

  • Оптимизировать петли.
    Как правило, циклы не нужно оптимизировать, если внутри них мало что сделано (а они занимают хороший процент времени).

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

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

  • Параллелизм.
    Параллелизм преследует две цели.
    1) Производительность, но это только работает до такой степени, что позволяет нескольким компонентам оборудования запускать запуск одновременно. Если оборудования нет, это не помогает. Больно.
    2) Ясность выражения, поэтому, например, коду пользовательского интерфейса не нужно беспокоиться о тяжелых вычислениях или одновременном выполнении сетевого ввода-вывода.

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

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

Я использовал JProfiler для профилирования нашего приложения. Но это не сильно помогло. Затем я использовал JHat. Используя JHat, вы не можете видеть кучу в реальном времени. Вы должны сделать дамп кучи, а затем проанализировать его. Использование OQL (Object Query Language) - хороший метод поиска утечек кучи.

0
ответ дан 1 December 2019 в 05:11
поделиться
Другие вопросы по тегам:

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