TGViewer
Гепардово гнездо Гепардово гнездо @gepardchan · 617 subscribers
Post #138 1.26K
Исключения в C++ и почему они такие медленные

Недавно читал статью, в которой рассказывается про тормоза исключений в C++ и про то, что можно с этим сделать. Ниже будет пересказ с моими дополнениями.

Начнем с причины, почему бросание исключений медленное. Дело в том, что для этого необходимо раскрутить стек до ближайшего подходящего catch. Но раскрутка стека реализована через глобальные таблицы, которые защищены mutex'ом (например, чтобы обработать случай, когда в программу динамически подгружается so'шка и хочет, чтобы ее исключения тоже обрабатывались). Очевидно, что в многопоточном коде при интенсивном использовании исключений этот mutex быстро станет bottleneck'ом и будет драматически замедлять программу.

В статье указывается, что попытки починить вышеописанную проблему (например, заменив mutex на rwlock) приведут либо к гонкам, либо к поломке ABI. А, как известно, C++ по странным историческим причинам могут использовать вместе с древними, собранными в виде so'шек библиотеками, из-за чего ABI никто ломать не хочет. И теперь все вынуждены жить вот с такими вот медленными исключениями :(

Указывается еще две проблемы с исключениями в текущем виде: 1) они нелокальны из-за std::current_exception() и 2) они требуют аллокации на куче и RTTI. Все это, в числе прочих, мешает оптимизациям компилятора, когда тот понимает, что вот в этой ветке выкинется вот это исключение, и мог бы здесь попытаться срезать углы на создании и выбрасывании.

Стоит отдельно упомянуть, что исключения на самом деле не zero cost, даже если они не кидаются: поддержка раскрутки стека раздувает размер бинаря и иногда заставляет компилятор генерить менее оптимальный код (потому что оптимизации помешают правильной раскрутке стека).

Авторы пишут, что если оставить семантику исключений в текущем виде, но ускорить раскрутку, то
Even with fully lock-free unwinding, we encountered some scalability issues with very high threads counts and high error rates (256 threads, 10% failure). These were far less severe than with current single-threaded unwinding, but nevertheless it is clear that the other parts of traditional exception handling do not scale either due to global state.
что как будто бы частично решает проблему, но не до конца.

Далее предлагаются разные способы ускорить механизм обработки ошибок, все без раскрутки стека. Удивительно, что std::expected<> показал себя не очень хорошо по скорости, хотя все остальные методы (boost::LEAF и throwing values) работают на аналогичных принципах.

Я бы хотел отдельно рассказать про throwing values, но про это читайте пост ниже :)
  • 👍 7
More from @gepardchan
  1. Sep 7, 2025Итак, расскажу о том, что я сделал еще давно, но про что все никак не доходили руки написа…
  2. Dec 10, 2024https://habr.com/ru/post/472970/ Статья 2019 года, то есть довольно старая, с учетом того,…
  3. Nov 30, 2024Сегодня читал про то, как Debian везде перешел на 64-х битный time_t. Изменение войдет в р…
  4. Nov 26, 2024https://www.ryanliptak.com/blog/every-rc-exe-bug-quirk-probably/ Не знаю, как вы, а я прос…
  5. Nov 22, 2024Еще про проклятые фичи баша https://yossarian.net/til/post/some-surprising-code-execution-…
  6. Nov 21, 2024Про переписывание истории В баше (а точнее, в GNU Readline, который используется башом), е…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →