пятница, 9 декабря 2011 г.

Dynamic linking considered harmful?

А оказывается, многие известные люди считают, что динамическое связывание это дурь и блажь. Серьёзное приложение-де не может находиться в зависимости от каких-то там обновляемых системных библиотек. В самом деле, от несанкционированных обновлений может быть не только польза (баг поправят, или там дыру закроют), но и серьёзный вред. При этом, оказывается, исправление бага в системной либе может быть полезно для одних приложений и вредно для других. Получается, и обновлять нельзя, и не обновлять нельзя.

Про поломку бинарной совместимости и говорить нечего, см. DLL Hell. Версионирование библиотек, придуманное для решения этой проблемы, по большому счёту только усугубляет её.

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

Статическое связывание, напротив, всё упрощает! Из-за отсутствия необходимости в PIC код становится много компактнее (что в большей части случаев перевешивает расходы на дублирование кода в приложениях), межмодульные оптимизации становятся возможны, плюс к тому экономятся драгоценные TLB. При этом ещё не надо забывать о том, что код нескольких копий одного процесса тоже является общим (равно как и код форкнутого процесса с родительским), то есть экономия памяти тоже не очень-то страдает.

Ещё одна причина, по которой используют динамически связываемые библиотеки — это разного рода плагины. Но для механизма плагинов этого динамическое связывание не является необходимостью. Достаточно динамической загрузки кода. Кстати, Windows DLL это как раз и есть динамически загружаемые, а не связываемые, библиотеки. Динамического связывания в Windows вообще нет. Код DLL не является position-independent.

Тут бы и подумать, что Windows со своими DLL идёт впереди прогресса, не поддаваясь на провокации. Но нет. Во-первых, само присутствие DLL как отдельных системных файлов порождает проблемы, о которых сказано в первых четырёх абзацах. Почему-то принято завязываться на DLL, а не линковать всё статически. Почему? Неизвестно.

Во-вторых, в Windows очень капризная libc. Она не переносит, когда память, выделенная в одном экземпляре, освобождается в другом! Из личного опыта скажу, что даже strcpy-ровать её нельзя, хотя по ссылке этого не написано. Что делает статическую линковку с libc бессмысленной в том случае, когда у вам есть более-менее сложные плагины. Приложения и их плагины должны линковаться с динамической libc. И вообще, в Windows море проблем с написанием плагинов.

Говорят (по самой первой ссылке) что в plan9 статическая линковка и всё при этом просто и удобно, в том числе с плагинами. Хотя и плагины там не очень нужны, при наличии 9P. Сам не пробовал, подтвердить не могу.

2 комментария:

Анонимный комментирует...

а вообще вот что нужно, так это динамическая загрузка модулей, как в Blackbox Component Pascal.

вот это пример того, как динамические библиотеки могут быть реализованы правильно.

Анонимный комментирует...

другой пример того, как эта же задача может быть решена проще:

объектная модель SOM в OS/2. минусы её в том, что это реализация тяжеловесной CORBA, а значит, маршаллинг и какая-то внутренняя жизнь при создании объектов, например работа с метаклассами.

плюсы же в том, что решается проблема с бинарной совместимостью "малой кровью": для того, чтобы сделать SOM объект с каким-то классом, достаточно экспортировать в DLL всего три функции (сравните это с тем, что порождает типичная библиотека на С++).

бинарная совместимость решается правильным проектированием структур, реализующих объекты: ClassDataObject, который содержит ссылку на метакласс и указатели на методы. заполняется в конструкторе класса, то есть, экспортировать все методы в библиотеку не нужно.

ещё в releaseorder поле в IDL указывается "раскладка" объекта в том виде, который не ломает бинарную совместимость.

да, и как в Blackbox Component Pascal здесь тоже методы привязаны к классам не так топорно, как в С++.

в итоге, имеем 2 системы, где динамические библиотеки реализованы правильно: SOM и Oberon-2, Blackbox Component Pascal.

или, "компонентное программирование" Клеменса Шиперски.

но они широко практически не известны и мало используются.