Как исключения реализованы под капотом?

Примерно все используют их, но многие, включая меня просто принимают как очевидное, что они просто работают.

Я ищу высококачественный материал. Языки, которые я использую: Java, C, C#, Python, C++, таким образом, они представляют большую часть интереса для меня.

Теперь, C++ является, вероятно, хорошим местом для запуска, так как можно бросить что-либо в тот язык.

Кроме того, C близко к блоку. Как можно было бы эмулировать исключения с помощью чистых конструкций C и никакого блока?

Наконец, я слышал слух, что сотрудники Google не используют исключения для некоторых проектов из-за соображений скорости. Это - просто слух? Как может что-либо существенное быть выполненным без них?

Спасибо.

64
задан Billy ONeal 8 June 2011 в 01:55
поделиться

10 ответов

Исключения - это просто частный пример более общего случая сложных нелокальных конструкций управления потоком. Другие примеры:

  • уведомления (обобщение исключений, первоначально из некоторой старой объектной системы Lisp, теперь реализованной, например, в CommonLisp и Ioke),
  • продолжения (более структурированная форма GOTO , популярный в языках высокого уровня и высшего порядка),
  • сопрограммы (обобщение подпрограмм, особенно популярных в Lua),
  • генераторы а-ля Python (по сути, ограниченный форма сопрограмм),
  • волокна (совместные легкие потоки) и, конечно же, уже упомянутый
  • GOTO .

(Я уверен, что я пропустил много других.)

Интересным свойством этих конструкций является то, что все они примерно эквивалентны по выразительной силе: если у вас есть один , вы можете довольно легко построить все остальные.

Итак, как лучше всего реализовать исключения, зависит от того, какие другие конструкции у вас есть:

  • Каждый процессор имеет GOTO , поэтому вы всегда можете вернуться к нему, если потребуется.
  • C имеет setjmp / longjmp , которые в основном представляют собой продолжения МакГайвера (построенные из клейкой ленты и зубочисток, не совсем реальная вещь, но по крайней мере вытащит вас немедленные проблемы, если у вас нет чего-то лучшего).
  • JVM и CLI имеют собственные исключения, а это означает, что если семантика исключений вашего языка совпадает с семантикой Java / C #, вы дома свободны (но если нет, то вы облажались).
  • Parrot VM как исключения и продолжения.
  • Windows имеет свою собственную структуру для обработки исключений, которую разработчики языка могут использовать для создания своих собственных исключений поверх.

Очень интересным вариантом использования использования исключений и реализации исключений является проект Volta от Microsoft Live Lab. (Сейчас не существует.) Целью Volta было обеспечить архитектурный рефакторинг для веб-приложений одним нажатием кнопки. Таким образом, вы можете превратить одноуровневое веб-приложение в двух- или трехуровневое приложение, просто поместив некоторые атрибуты [Браузер] или [DB] в свой код .NET и код будет автоматически запускаться на клиенте или в БД. Очевидно, для этого код .NET должен был быть переведен в исходный код JavaScript.

Теперь вы можете просто написать всю виртуальную машину на JavaScript и запустить байт-код без изменений. (По сути, портируйте CLR с C ++ на JavaScript.) На самом деле существуют проекты, которые это делают (например, виртуальная машина HotRuby), но это неэффективно и не очень совместимо с другим кодом JavaScript.

Вместо этого они написали компилятор, который компилирует байт-код CIL в исходный код JavaScript. Однако в JavaScript отсутствуют некоторые функции, которые есть в .NET (генераторы, потоки, а также две модели исключений не совместимы на 100%), и, что более важно, в нем отсутствуют определенные функции, которые нравятся разработчикам компиляторов (либо GOTO или продолжения), которые можно использовать для реализации вышеупомянутых недостающих функций.

Однако в JavaScript есть исключения . Итак, они использовали Исключения JavaScript для реализации Продолжений Вольта , а затем они использовали Продолжения Вольта для реализации Исключений .NET , . Генераторы .NET и даже Управляемые потоки .NET (!!!)

Итак, чтобы ответить на ваш исходный вопрос:

Как исключения реализуются под капотом?

С исключениями, как ни странно! По крайней мере, в этом очень конкретном случае.

Другой замечательный пример - некоторые предложения по исключениям в списке рассылки Go, которые реализуют исключения с использованием горутин (что-то вроде смеси параллельных сопрограмм и процессов CSP). Еще один пример - Haskell, который использует монады, ленивую оценку, оптимизацию хвостового вызова и функции высшего порядка для реализации исключений. Некоторые современные процессоры также поддерживают базовые строительные блоки для исключений (например, процессоры Vega-3, которые были специально разработаны для ускорителей вычислений Java Azul Systems).

41
ответ дан 24 November 2019 в 15:54
поделиться

Реализованы исключения из C++:
http://www.codesourcery.com/public/cxx-abi/abi-eh.html

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

Вот хорошее описание того, как LLVM реализует исключения:
http://llvm.org/docs/ExceptionHandling.html

Так как LLVM задумана как общее промежуточное представление для многих периодов выполнения, описанные механизмы могут быть применены ко многим языкам.

.
22
ответ дан 24 November 2019 в 15:54
поделиться

В его книге C Интерфейсы и внедрения: Методы создания многоразового программного обеспечения, Д. Р. Хансон обеспечивает хорошую реализацию исключений на чистом языке Си с использованием набора макросов и setjmp/долгое время. Он предоставляет макросы TRY/RAISE/EXCEPT/FINALLY, которые могут эмулировать практически все, что делают исключения на C++ и многое другое.

Код можно посмотреть здесь (смотрите на except.h/except.c).

P.S. - это ваш вопрос о Google. На самом деле их сотрудникам разрешено использовать исключения в новом коде, а официальная причина запрета в старом состоит в том, что он уже был написан таким образом и смешивать стили не имеет смысла.

Лично я также считаю, что Си++ без исключений - не самая лучшая идея.

.
17
ответ дан 24 November 2019 в 15:54
поделиться

Компиляторы C/C++ используют базовые средства операционной системы для обработки исключений. Такие фреймворки, как .Net или Java также полагаются в ВМ на возможности ОС. В Windows, например, реальную тяжелую работу выполняет SEH, инфраструктура структурированной обработки исключений. Вам обязательно стоит прочитать старую справочную статью: Аварийный курс на глубинах Win32™ Structured Exception Handling.

Что касается стоимости отказа от использования исключений, то они дорогостоящие, но по сравнению с чем? По сравнению с кодами ошибок возврата? После того, как вы учтете стоимость корректности и качество кода, исключения всегда выигрывают для коммерческих приложений. Не считая нескольких очень критичных функций на уровне ОС, исключения в целом всегда лучше.

И последнее, но не менее важное: существует анти-маскарад использования исключений для управления потоком. Исключения должны быть исключительными и код, злоупотребляющий исключениями для управления потоком, заплатит за производительность

.
7
ответ дан 24 November 2019 в 15:54
поделиться

Ключевая вещь, с которой необходимо справиться при реализации исключения, это как вернуться к обработчику исключения после того, как оно было брошено. Так как с момента выполнения оператора try на C++ могло произойти произвольное количество вызовов вложенных функций, то он должен размотать стек вызовов в поисках обработчика. Однако реализованная операция должна стоить размера кода поддержания достаточного количества информации для выполнения этой операции (и обычно означает таблицу данных для вызовов, которые могут принимать исключения). Это также означает, что динамический путь выполнения кода будет длиннее , чем простой возврат от вызовов функций (что является довольно недорогой операцией на большинстве платформ). В зависимости от реализации могут быть и другие затраты.

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

Приложение, в котором использование исключений (и Си++ в целом) часто избегается по уважительным причинам, является встроенной прошивкой. В типичных небольших платформах на пустом металле или RTOS, у вас может быть 1 МБ кодового пространства, или 64К, или даже меньше. Некоторые платформы настолько малы, что даже Си использовать нецелесообразно. В таких средах влияние размеров актуально из-за стоимости, упомянутой выше. Это также влияет на саму стандартную библиотеку. Производители встраиваемых инструментальных цепей часто выпускают библиотеку без исключений, что оказывает огромное влияние на размер кода. Высоко оптимизирующие компиляторы также могут анализировать график вызовов и оптимизировать информацию о кадре вызова для выполнения операции размотки для значительного уменьшения занимаемого места. Исключения также усложняют анализ требований к жесткому реальному времени.

В более типичных средах размер кода почти наверняка не имеет значения, а фактор производительности, скорее всего, является ключевым. Будете ли вы их использовать, будет зависеть от ваших требований к производительности и от того, как вы хотите их использовать. Использование исключений в неисключительных случаях может сделать элегантный дизайн, но при стоимости производительности, которая может быть неприемлема для высокопроизводительных систем. Воплощения и относительная стоимость будут варьироваться в зависимости от платформы и компилятора, поэтому лучший способ по-настоящему понять, являются ли исключения проблемой, - это проанализировать производительность собственного кода.

.
4
ответ дан 24 November 2019 в 15:54
поделиться

setjmp() и longjmp() обычно.

Исключение ловли имеет нетривиальную стоимость, но для большинства целей это не имеет большого значения.

4
ответ дан 24 November 2019 в 15:54
поделиться

C++ код в Google (за исключением некоторых Windows-специфических случаев) не используют исключения: cfr руководство , сокращенная форма: "Мы не используем исключения на Си++". Цитата из обсуждения (нажатие на стрелку для расширения URL):

Наш совет против использования исключений состоит в следующем не основанный на философских соображениях или моральные основания, но практические. Потому что мы хотели бы использовать наши проекты с открытым исходным кодом в Google и это трудно сделать, если эти в проектах используются исключения, нам нужно не допускать исключений в Google Также проекты с открытым исходным кодом. Вещи наверное, было бы иначе, если бы мы делать все заново с нуля.

Это правило не применяется к коду Google на других языках, таких как Java и Python.

.
3
ответ дан 24 November 2019 в 15:54
поделиться

Что касается производительности - редкое использование исключений, вероятно, будет иметь незначительные эффекты, но не злоупотреблять ими.

Я лично видел Java-код, который выполнял на два порядка хуже, чем он мог бы иметь (занял около x100 времени), потому что исключения использовались в важном цикле вместо более стандартных if/возвратов.

.
1
ответ дан 24 November 2019 в 15:54
поделиться

В некоторых исполнениях, как Objective-C runtime, есть 64-битные исключения с нулевой стоимостью. Это означает, что вход в блок try ничего не стоит. Однако, это довольно дорого стоит, когда выбрасывается исключение. Это следует парадигме "оптимизация для среднего случая" - исключения предназначены для исключения, поэтому лучше сделать так, чтобы исключение не было действительно быстрым, даже если оно достигается ценой значительно более медленных исключений.

.
1
ответ дан 24 November 2019 в 15:54
поделиться

Лучшая работа, когда-либо написанная по реализации исключений (под капотом) - это Исключения, обработанные в CLU Барбарой Лисковой и Аланом Снайдером. Я ссылался на нее каждый раз, когда запускал новый компилятор.

Для более высокоуровневого представления реализации на Си с использованием setjmp и longjmp я рекомендую интерфейсы и имплементации C Дэйва Хэнсона (как Эли Бендерски).

6
ответ дан 24 November 2019 в 15:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: