← На главную

jank устранил проблемы с компиляцией C++

15.05.2026 17:17 · hackernews

Легенда о том, что «C++ медленный», часто возникает у тех, кто видит исходный код, написанный на C++, и сравнивает его с «магическим» исполнением JVM. Однако скорость языка не определяется только его синтаксисом. Скорость зависит от того, как этот код компилируется, какие оптимизации применяются и как организована работа с памятью.

Вот краткий разбор того, почему C++ может показаться медленным без должного подхода, и как в примере с проектом jank все исправлено:

  1. Отсутствие автоматической оптимизации: В отличие от компиляторов JVM, которые годами накапливают сложные техники оптимизации, компиляторы C++ (даже современные) часто требуют явных указаний от разработчика.
  2. Автоматическое наведение ящиков (Boxing): Если не использовать специальные приемы, любой примитивный тип данных (например, int) в C++ превращается в объект на куче (например, std::unique_ptr<std::shared_ptr<jank::runtime::object_ref>). Это создает нагрузку на сборщик мусора (GC), как это было в примере с функциями add и sub в jank.
  3. Инлайн-функции: Без использования директив (например, [[gnu::always_inline]]), маленькие функции вызывают накладные расходы на переходы между функциями (branch misprediction).
  4. Использование виртуальных таблиц: По умолчанию в C++ полиморфизм использует виртуальные таблицы, что приводит к дополнительным вызовам (vtable lookups).

Автор проекта применил несколько ключевых оптимизаций, которые превратили медленный код в быстрый:

  1. Избегание Boxing: Использование into-object и truthy было устранено, что ускорило выполнение программы.
  2. Настройка линкера и компилятора: Использование директив [[gnu::always_inline]] и [[gnu::flatten]] позволило объединить функции в один поток, ускорив обработку арифметических операций.
  3. Tagged Pointers (Затегированные указатели): Использование нижних битов указателей для хранения целых чисел позволило избежать выделений памяти для небольших чисел.
  4. Оптимизация использования NULL: Вместо вызова функции jank_nil, которая вызывала дополнительные накладные расходы, было принято решение использовать глобальные переменные с конструкторами, которые инициализируют значение в nullptr.

C++ — один из самых мощных и гибких языков программирования, который позволяет достичь производительности, сопоставимой с JVM, при правильном подходе. В примере с jank автор демонстрирует, что даже с использованием C++, можно достичь скорости, превосходящей Java, если учесть особенности работы с памятью и использовать современные приемы оптимизации.

В будущем, как ожидается, jank сможет конкурировать с JVM еще активнее, особенно учитывая возможность использовать асинхронную модель выполнения, которая может дать преимущество над блокирующей моделью JVM в некоторых задачах.

Читать оригинал →