Если вы прочитаете байт-код, вы можете увидеть, что компилятор не очень хорошо оптимизирует код. Однако JIT может оптимизировать код, так что это действительно не имеет значения.
Допустим, вы скомпилировали код на компьютере с архитектурой x86 и появилась новая архитектура, назовем ее x64, тот же двоичный файл Java может воспользоваться преимуществами новых возможностей этой архитектуры, даже если он не существовал на момент компиляции кода. Это означает, что вы можете использовать старые дистрибутивы библиотек и использовать новейшие аппаратные оптимизации. Вы не можете сделать это с C / C ++.
Java может оптимизировать встроенные вызовы для виртуальных методов. Допустим, у вас есть виртуальный метод с множеством возможных реализаций. Однако, скажем, одна или две реализации в большинстве случаев вызываются в реальности. JIT может обнаружить это и встроить до двух реализаций метода, но все равно будет вести себя корректно, если вам случится вызвать другую реализацию. Вы не можете сделать это с C / C ++
Java 7 поддерживает анализ экранирования для заблокированных / синхронизированных объектов, он может обнаружить, что объект используется только в локальном контексте, и удалить синхронизацию для этого объекта.
В текущих версиях Java он может определять, блокируют ли два последовательных метода один и тот же объект, и сохранять блокировку между ними (вместо того, чтобы освобождать и повторно получать блокировку)
Вы не можете сделать это с C / C ++, потому что нет понимания уровня блокировки языка.