Почему 64-битная JVM быстрее, чем 32-битная?

Недавно я проводил бенчмаркинг производительности записи продукта моей компании, и я обнаружил, что просто переход на 64-битную JVM дает постоянное увеличение производительности на 20-30%.

Мне не разрешено подробно рассказывать о нашем продукте, но в основном это колонка-ориентированная БД, оптимизированная для хранения журналов. Этот тест включает в себя загрузку нескольких гигабайт необработанных журналов и время, необходимое для их анализа и хранения в виде структурированных данных в БД. Обработка очень тяжелая как на CPU, так и на I/O, хотя в каком отношении трудно сказать.

Несколько заметок о настройке:

Processor: Xeon E5640 2.66GHz (4 core) x 2
RAM: 24GB
Disk: 7200rpm, no RAID
OS: RHEL 6 64bit
Filesystem: Ext4
JVMs: 1.6.0_21 (32bit), 1.6.0_23 (64bit)
Max heap size (-Xmx): 512 MB (for both 32bit and 64bit JVMs)

Константы для обоих JVM:

  • Одинаковая ОС (64-битная RHEL)
  • То же аппаратное обеспечение (64-битный процессор)
  • Максимальный размер кучи фиксирован на 512 МБ (поэтому увеличение скорости происходит не из-за 64-битной JVM с использованием большей кучи)

Для простоты я отключил все варианты многопоточности в нашем продукте, так что практически вся обработка происходит однопоточно. (Когда я включил многопоточность, конечно, система стала быстрее, но соотношение между 32-битной и 64-битной характеристиками оставалось примерно одинаковым.)

Итак, мой вопрос... Почему я должен видеть улучшение скорости на 20-30% при использовании 64-битной JVM? Кто-нибудь видел подобные результаты раньше?

Моя интуиция до сих пор была следующей:

  • 64-битные указатели больше, поэтому L1 и L2 кэшируют более легко, поэтому производительность на 64-битной JVM хуже.

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

  • JVM разрешено использовать больше регистров при работе в режиме 64 бит, что немного ускоряет работу.

Учитывая вышеуказанные три точки, я ожидал бы, что 64-битная производительность будет немного медленнее или примерно равна 32-битной JVM.

Любые идеи? Спасибо заранее.

Изменить: Разъяснены некоторые моменты в тестовой среде.

Ответы

Ответ 1

Не зная своего оборудования, я просто беру некоторые дикие удары

  • В вашем конкретном процессоре может использоваться микрокод для эмуляции некоторых инструкций x86 - в первую очередь, x87 ISA
  • x64 использует sse math вместо математики x87, я заметил, что в этом случае некоторые 10% -ные 20% -ые ускорения некоторых приложений на С++. Различия в математике могут быть реальным убийцей, если вы используете strictfp.
  • Память. 64 бит дает вам гораздо больше адресного пространства. Может быть, GC немного менее агрессивен в режиме 64 бит, потому что у вас есть дополнительная оперативная память.
  • Является ли ваша ОС в режиме 64b и запущена 32-битная jvm с помощью некоторой утилиты-оболочки?

Ответ 2

От: http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#64bit_performance

"Как правило, преимущества использования большего объема памяти приносят небольшую потерю производительности в 64-битных виртуальных машинах по сравнению с тем же приложением на 32-разрядной виртуальной машине. Это связано с тем, что каждый собственный указатель в системе занимает 8 байт вместо 4. Загрузка этих дополнительных данных влияет на использование памяти, что приводит к чуть более медленному выполнению в зависимости от того, сколько указателей загружается во время выполнения вашей Java-программы. Хорошей новостью является то, что с AMD64 и EM64T, работающие в 64-битном режиме, виртуальная машина Java получает некоторые дополнительные регистры, которые она может использовать для создания более эффективных встроенных инструкций. Эти дополнительные регистры увеличивают производительность до такой степени, что при сравнении 32 до 64-битной скорости выполнения.
Разница в производительности, сравнивая приложение, работающее на 64-битной платформе, и 32-разрядную платформу SPARC, происходит при декомпрессии 10-20% при переходе на 64-разрядную виртуальную машину. На платформах AMD64 и EM64T это различие колеблется от 0-15% в зависимости от количества указателей, обращающихся к вашему приложению. "

Ответ 3

Мое лучшее предположение, основанное на быстрой версии Google для 32-битных графиков производительности, что 64-разрядный ввод-вывод более эффективен. Я полагаю, вы много делаете в/в...

Если memcpy задействован при перемещении данных, вероятно, более эффективно копировать longs, чем ints.

Ответ 4

В 64-битном наборе команд имеется еще 8 регистров, это должно сделать код более быстрым.

Но поскольку процессы в настоящее время в основном ждут памяти или диска, я полагаю, что либо подсистема памяти, либо диск i/o могут быть более эффективными в 64-битном режиме.

Ответ 5

Поймите, что 64-битная JVM - это не волшебная пыль пикселов, которая делает приложения Java быстрее. 64-битная JVM позволяет кучи → 4 ГБ и, как таковые, имеет смысл только для приложений, которые могут использовать огромную память для систем, которые имейте это.

Как правило, либо небольшое улучшение (из-за определенного оборудования оптимизация на определенных платформах) или незначительная деградация (из-за увеличения размер указателя). Вообще говоря, потребуется меньше GC - но когда они действительно происходят, они, вероятно, будут длиннее.

В базах данных или поисковых системах, которые могут использовать увеличенную память для кэширования объектов и, таким образом, избежать доступа к IPC или дискам, вы увидите самый большой улучшения уровня приложения. Кроме того, 64-битная JVM также будет позволяют запускать много и много потоков, чем 32-битные, потому что там больше адресного пространства для таких вещей, как потоки стеков и т.д. максимальное количество потоков в общем случае для 32-разрядной JVM составляет ~ 1000 бит ~ 100000 потоков с 64-разрядной JVM.

Некоторые недостатки:
Дополнительные проблемы с 64-битной JVM заключаются в том, что определенный клиент ориентированные функции, такие как Java Plug-in и Java Web Start не поддерживаются. Также необходим и любой нативный код (например, JNI для таких вещей, как драйверы JDBC типа II). Это бонус для чистых разработчиков Java, поскольку чистые приложения должны просто выбегайте из коробки.

Подробнее об этой теме на Java.net