Я о проводить профилирование в мастерской, настройку производительности, профилирование памяти, обнаружение утечек памяти и т. д. Java-приложений с использованием JProfiler и Eclipse Tptp. Мне нужен комплекс упражнений, которые я мог бы предложить участникам, где они могут: Используйте инструмент, чтобы профилировать обнаружение проблемы: узкое место, утечка памяти, неоптимальный код и т. Д. Я уверен, что вокруг достаточно опыта и реальных примеров.
Проблемы и решения не должны быть чрезмерно сложными; их можно решить в считанные минуты, в лучшем случае - в считанные часы. Некоторые интересные области для упражнений:
В идеале упражнения должны включать образец неоптимизированного кода и код решения.
Я пытаюсь найти примеры из реальной жизни, которые я видел в дикой природе (возможно, немного измененные, но все основные проблемы были вполне реальными). Я также попытался сгруппировать их по одному и тому же сценарию, чтобы вы могли легко создать сеанс.
Сценарий: у вас есть трудоемкая функция, которую вы хотите выполнить много раз для разных значений, но одни и те же значения могут появиться снова (в идеале не слишком долго после того, как они были созданы). Хорошим и простым примером являются пары URL-адрес веб-страницы, которые вам необходимо загрузить и обработать (для упражнения это, вероятно, должно быть смоделировано).
Циклы:
Вы хотите проверить, не всплывает ли какой-либо набор слов на страницах. Используйте вашу функцию в цикле, но с тем же значением, псевдокод:
for (word: words) {
checkWord (скачать (url))
}
Одно из решений довольно простое: просто загрузите страницу до цикла. Другое решение ниже.
Утечка памяти:
WeakHashMap
, где ключи - это URL-адреса (НЕ в виде строк, см. Ниже), значения - это экземпляры класса, который содержит URL, загруженный страница и еще кое-что. Вы можете предположить, что все должно быть в порядке, но на самом деле это не так: поскольку значение (которое не имеет слабой ссылки) имеет ссылку на ключ (URL-адрес), ключ никогда не сможет очистить -> хорошая утечка памяти . Создание объекта и строки:
Параллелизм:
Вы хотите ускорить весь процесс, выполняя загрузку / фильтрацию параллельно. Создайте несколько потоков и запустите свой код, используя их, но все делайте внутри большого синхронизированного блока (на основе кеша), просто «чтобы защитить кеш от проблем параллелизма». Эффект должен заключаться в том, что вы эффективно используете только один поток, поскольку все остальные ждут блокировки кеша.
Решение: синхронизируйте только операции с кешем (например, используйте `java.util.collections.synchronizedMap ())
Синхронизируйте все крошечные кусочки кода. Это должно убить производительность и, возможно, помешать нормальному параллельному выполнению. Если вам повезет / вы достаточно умны, вы также можете придумать тупиковый замок. Мораль этого: синхронизация должна быть не спонтанной, «не повредит», а хорошо продуманной вещью.
Дополнительное упражнение:
Заполните кэш вначале и не делайте слишком много памяти после, но все же где-то есть небольшая утечка. Обычно эту закономерность не так-то просто уловить. Вы можете использовать функцию «закладки» или «водяного знака» профилировщика, которая должна быть создана сразу после завершения кэширования.
Не игнорируйте этот метод , потому что он очень хорошо работает для любого языка и ОС по этим причинам . Пример здесь . Также попробуйте использовать примеры с вводом-выводом и значительной глубиной вызова. Не используйте только маленькие программы с привязкой к процессору, такие как Мандельброт. Если вы возьмете этот пример C, который не слишком велик, и перекодируете его на Java, это должно проиллюстрировать большинство ваших соображений.
Посмотрим:
Устранение утечек памяти.
Весь смысл сборщика мусора заключается в устранении утечек памяти. Однако вы все равно можете выделить слишком много памяти, и для некоторых объектов это проявляется как большой процент времени в «новом».
Оптимизировать петли.
Как правило, циклы не нужно оптимизировать, если внутри них мало что сделано (а они занимают хороший процент времени).
Оптимизировать создание объектов и управление ими.
Основной подход здесь: сохраняйте структуру данных как можно более простой. В особенности держитесь подальше от попыток сохранить согласованность данных в стиле уведомлений, потому что эти вещи убегают и делают дерево вызовов чрезвычайно густым. Это основная причина проблем с производительностью в большом программном обеспечении.
Оптимизация строковых операций.
Используйте построитель строк, но не переживайте за код, который не использует твердый процент времени выполнения.
Параллелизм.
Параллелизм преследует две цели.
1) Производительность, но это только работает до такой степени, что позволяет нескольким компонентам оборудования запускать запуск одновременно. Если оборудования нет, это не помогает. Больно.
2) Ясность выражения, поэтому, например, коду пользовательского интерфейса не нужно беспокоиться о тяжелых вычислениях или одновременном выполнении сетевого ввода-вывода.
В любом случае, это невозможно переоценить, не проводите оптимизацию, пока не докажете, что что-то занимает значительный процент времени.
Я использовал JProfiler для профилирования нашего приложения. Но это не сильно помогло. Затем я использовал JHat. Используя JHat, вы не можете видеть кучу в реальном времени. Вы должны сделать дамп кучи, а затем проанализировать его. Использование OQL (Object Query Language) - хороший метод поиска утечек кучи.