Какова типичная скорость выделения памяти в Java? - PullRequest
4 голосов
/ 28 декабря 2011

Я профилировал приложение Java и обнаружил, что распределение объектов происходит значительно медленнее, чем я ожидал.Я выполнил простой тест, пытаясь установить общую скорость выделения небольших объектов, и обнаружил, что выделение небольшого объекта (вектор из 3 поплавков), похоже, занимает около 200 наносекунд на моей машине.Я использую двухъядерный процессор с тактовой частотой 2,0 ГГц, так что это примерно 400 тактов процессора.Я хотел спросить здесь людей, которые профилировали приложения Java прежде, стоит ли ожидать такой скорости.Это кажется немного жестоким и необычным для меня.В конце концов, я бы подумал, что язык, подобный Java, который может сжимать кучу и перемещать объекты, будет иметь распределение объектов, которое будет выглядеть примерно так:

int obj_addr = heap_ptr;
heap_ptr += some_constant_size_of_object
return obj_addr;

...., который представляет собой пару строк сборки.Что касается сбора мусора, я не выделяю и не выбрасываю достаточно объектов, чтобы это вступило в игру.Когда я оптимизирую свой код путем повторного использования объектов, я получаю производительность порядка 15 наносекунд / объект, который мне нужно обрабатывать вместо 200 нс на объект, который мне нужно обрабатывать, поэтому повторное использование объектов значительно повышает производительность.Я действительно не хотел бы повторно использовать объекты, потому что это делает обозначение волосатым (многие методы должны принимать аргумент receptacle вместо возврата значения).

Итак, вопрос в том, является ли этот объект нормальнымраспределение занимает так много времени?Или может быть что-то не так на моей машине, что после исправления может позволить мне иметь более высокую производительность на этом?Сколько времени обычно занимает выделение мелких объектов для других, и есть ли типичное значение?Я сейчас использую клиентскую машину и не использую флаги компиляции.Если на вашей машине все работает быстрее, какая у вас версия JVM и операционная система?

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

Ответы [ 3 ]

4 голосов
/ 28 декабря 2011

Создание объектов очень быстрое, когда объект маленький и стоимость GC отсутствует.

final int batch = 1000 * 1000;

Double[] doubles = new Double[batch];
long start = System.nanoTime();

    for (int j = 0; j < batch; j++)
        doubles[j] = (double) j;

long time = System.nanoTime() - start;
System.out.printf("Average object allocation took %.1f ns.%n", (double) time/batch);

печатает с -verbosegc

Average object allocation took 13.0 ns.

Примечание.Однако, увеличьте размер, и программе нужно подождать, чтобы скопировать память в ГХ.,Одним из способов решения этой проблемы является увеличение памяти, доступной для приложения.(Хотя это может просто задержать стоимость)

Если я запусту его снова с -verbosegc -XX:NewSize=1g

Average object allocation took 9.1 ns.
2 голосов
/ 28 декабря 2011

Я не знаю, как вы измеряете время распределения.Вероятно, он встроен, по крайней мере, эквивалентно

intptr_t obj_addr = heap_ptr;
heap_ptr += CONSTANT_SIZE;
if (heap_ptr > young_region_limit) 
    call_the_garbage_collector ();
return obj_addr;

Но это более сложный вариант, потому что вы должны заполнить obj_addr;тогда может произойти некоторая JIT-компиляция или загрузка классов ;и очень вероятно, что первые несколько слов инициализируются (например, указателю класса и хэш-коду, который может включать в себя генерацию случайных чисел ...), и вызываются конструкторы объектов.Для них может потребоваться синхронизация и т. Д.

И что более важно, недавно выделенный объект, возможно, не находится в ближайшем кеше первого уровня, поэтому возможны некоторые ошибки в кешировании.эксперт по Java, я не удивлен вашими мерами.Я действительно считаю, что выделение новых объектов делает ваш код более чистым и более понятным, чем повторное использование старых объектов.

1 голос
/ 28 декабря 2011

Да. Разница между тем, что, по вашему мнению, должно быть сделано, и тем, что он делает на самом деле, может быть довольно большой. Объединение может быть грязным, но когда выделение и сборка мусора занимает большую часть времени выполнения, что, безусловно, может быть, объединение - это большой выигрыш с точки зрения производительности.

Объекты для объединения - это те, которые вы чаще всего находите в процессе выделения с помощью образцов стека.

Вот как выглядит такой пример в C ++. В Java детали разные, но идея та же:

... blah blah system stuff ...
MSVCRTD! 102129f9()
MSVCRTD! 1021297f()
operator new() line 373 + 22 bytes
operator new() line 65 + 19 bytes
COpReq::Handler() line 139 + 17 bytes <----- here is the line that's doing it
doit() line 346 + 12 bytes
main() line 367
mainCRTStartup() line 338 + 17 bytes
KERNEL32! 7c817077()
                              V------ and that line shows what's being allocated
        COperation* pOp = new COperation(iNextOp++, jobid);
...