Бенчмаркинг внутри Java-кода
В последнее время я изучаю бенчмаркинг, меня всегда интересовали протоколирование данных программы и т.д. Мне было интересно узнать, можем ли мы реализовать собственный код использования памяти и эффективно реализовать наш собственный код потребления времени внутри нашей программы. Я знаю, как проверить, сколько времени требуется для запуска кода:
public static void main(String[]args){
long start = System.currentTimeMillis();
// code
System.out.println(System.currentTimeMillis() - start);
}
Я также рассмотрел Надежный Java-бенчмаркинг, часть 1: Проблемы, этот урок очень всеобъемлющий. Отображает отрицательные эффекты System.currentTimeMillis();
. Затем в учебнике предлагается использовать System.nanoTime();
(что делает его более точным?).
Я также рассмотрел Определение использования памяти в Java для использования в памяти. На веб-сайте показано, как вы можете его реализовать. Код, который был предоставлен, выглядит неэффективным, потому что человек звонит
long L = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
После этого он называет System.gc();
(4 * 4) = 16 раз. Затем повторите процесс снова.
Разве это не занимает память?
Итак, можно ли встраивать эффективный бенчмаркинг в вашу Java-программу?
Ответы
Ответ 1
Да, можно эффективно реализовать тесты производительности в Java-коде. Важный вопрос заключается в том, что любой из этапов производительности будет добавлять свои собственные накладные расходы и сколько из них вы хотите. System.currentMill..() является достаточно хорошим эталоном производительности, и в большинстве случаев nanoTime() является излишним.
Для памяти System.gc отобразит различные результаты для разных прогонов (поскольку gc-run никогда не гарантируется.) Обычно я использую Visual VM для профилирования памяти (ее бесплатно), а затем использую TDA для анализа дампов.
Один из способов сделать это менее инвазивным - использовать аспект ориентированную программирование. Вы можете создать только один аспект, который запускается на определенной аннотации или наборе методов, и напишите совет @Around для сбора данных о производительности.
Вот небольшой фрагмент:
public class TestAspect {
@LogPerformance
public void thisMethodNeedsToBeMonitored(){
// Do Something
}
public void thisMethodNeedsToBeMonitoredToo(){
// Do Something
}
}
@interface LogPerformance{}
@Aspect
class PerformanceAspect{
@Around("the pointcut expression to pick up all " +
"the @PerfMonitor annotated methods")
public void logPerformance(){
// log performance here
// Log it to a file
}
}
Ответ 2
Возможно, невозможно измерить без какого-либо эффекта Гейзенберга, т.е. также будет измерен ваш скамьежный код. Однако, если вы измеряете с достаточно высокой степенью детализации, эффект будет незначительным.
Ответ 3
Любой код бенчмаркинга будет менее эффективным, чем не-бенчмаркированный код, основанный на том, чтобы иметь больше возможностей для работы. Тем не менее, Java, в частности, вызывает проблемы, о которых говорится в статье, из-за того, что сбор мусора происходит каждый раз, когда это похоже на jre. Даже в документации для System.gc говорится, что он делает "лучшее усилие".
Что касается ваших конкретных вопросов:
System.gc не должен занимать больше памяти, но для этого потребуются ресурсы процессора.
Это несколько возможно на основе того, что вы пытаетесь сравнить. Там будет какое-то вмешательство. Если вы хотите выйти за пределы своего кода, есть инструменты, такие как VisualVM, для просмотра использования памяти вне вашего приложения.
Изменить: Исправлена формулировка того, что говорят System.gc.