Профилирование Java код изменяет время выполнения - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь оптимизировать свой код, но это доставляет мне проблемы. У меня есть этот список объектов:

List<DataDescriptor> descriptors;

public class DataDescriptor {
    public int id;
    public String name;
}

1700 объектов с уникальным идентификатором (0-1699) и некоторым именем, оно используется для декодирования того, какой тип данных я получу позже.

Метод, который я пытаюсь оптимизировать, работает следующим образом:

    public void processData(ArrayList<DataDescriptor> descriptors, ArrayList<IncomingData> incomingDataList) {
        for (IncomingData data : incomingDataList) {
            DataDescriptor desc = descriptors.get(data.getDataDescriptorId());

            if (desc.getName().equals("datatype_1")) {
                 doOperationOne(data);
            } else if (desc.getName().equals("datatype_2")) {
                 doOperationTwo(data);
            } else if ....
                .
                .
            } else if (desc.getName().equals("datatype_16")) {
                 doOperationSixteen(data);
            }
        }
    }

Этот метод вызывается примерно миллионы раз при обработке файла данных, и каждый раз, когда входящийDataList содержит около 60 элементов, поэтому этот набор операторов if / elses выполняется около 60 миллионов раз.

Это занимает около 15 секунд на моем рабочем столе (i7-8700).

Изменение кода для проверки целочисленных идентификаторов вместо строк, очевидно, сбрасывает несколько секунд, что хорошо, но я надеялся на большее :) Я попробовал профилирование с использованием VisualVM, но для этого метода (с тестированием строк) говорится, что 66% времени тратится на "Self time" (который, я считаю, будет всем этим тестированием строк?) почему он не говорит, что он в методе String.equals?) и 33% тратится на descriptors.get - это просто получить из ArrayList, и я не думаю, что смогу оптимизировать его дальше, кроме tryi Чтобы изменить структуру данных в памяти (все же, это Java, поэтому я не знаю, поможет ли это много).

Я написал приложение "простой тест", чтобы изолировать сравнение String против int. Как я и ожидал, сравнение целых чисел было примерно в 10 раз быстрее, чем String.equals, когда я просто запускал приложение, но когда я профилировал его в VisualVM (я хотел проверить, не слишком ли медленно работает тест производительности ArrayList.get), как ни странно, оба метода потребовали точно такое же количество времени. При использовании образца VisualVM вместо профиля приложение завершало работу с ожидаемыми результатами (целые числа были в 10 раз быстрее), но VisualVM показывал, что в его примере оба типа сравнения занимали одинаковое количество времени.

В чем причина? для получения таких совершенно разных результатов при профилировании и нет? Я знаю, что есть много факторов, есть JIT, и профилирование может помешать этому и т. Д. c. - но, в конце концов, как вы профилируете и оптимизируете код Java, когда инструменты профилирования изменяют работу кода? (если это так)

1 Ответ

1 голос
/ 01 мая 2020

Профилировщики можно разделить на две категории: инструменты и выборка. VisualVM включает и то и другое, но оба они имеют недостатки.

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

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

Профилировщики выборки обычно имеют гораздо меньшие издержки; Более того, эти издержки являются управляемыми, поскольку они напрямую зависят от интервала профилирования, то есть от того, как часто профилировщик делает снимки потоков.

Проблема с профилировщиками выборки заключается в том, что JDK publi c API для получения трассировок стека имеет недостатки , JVM не получает трассировку стека в любой произвольный момент времени. Скорее он останавливает поток в одном из предопределенных мест, где он знает, как надежно пройтись по стеку. Эти места называются safepoints . Безопасные точки расположены на выходах методов (исключая встроенные методы) и внутри циклов (исключая циклы с коротким счетом). Вот почему, если у вас длинный линейный код или короткое число l oop, вы никогда не увидите его в профилировщике выборки, который использует стандарт JVM getStackTrace API.

Эта проблема известный как Safepoint Bias . Это хорошо описано в великом посте Ницана Вакарта. VisualVM не единственная жертва. Многие другие профилировщики, в том числе коммерческие инструменты, также страдают от той же проблемы, поскольку исходная проблема заключается в JVM, а не в конкретном инструменте профилирования.

Java Flight Recorder - это значительно лучше до тех пор, пока это не зависит от безопасных точек. Однако он имеет свой собственный fl aws: например, он не может получить трассировку стека, когда поток выполняет определенные методы JVM intrinsi c, такие как System.arraycopy. Это особенно разочаровывает, поскольку arraycopy является частым узким местом в Java приложениях.

Попробуйте asyn c -profiler . Целью проекта является именно решение вышеуказанных проблем. Он должен обеспечивать четкое представление о производительности приложения при очень небольших накладных расходах. asyn c -профиль работает на Linux и macOS. Если вы используете Windows, JFR по-прежнему будет вашим лучшим выбором.

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