Почему запуск приложения в Linux происходит медленнее при использовании общих библиотек?
-
05-07-2019 - |
Вопрос
На встроенном устройстве, над которым я работаю, время запуска является важной проблемой.Все приложение состоит из нескольких исполняемых файлов, которые используют набор библиотек.Поскольку место во ФЛЭШ-памяти ограничено, мы хотели бы использовать общие библиотеки.
Приложение работает как обычно, когда оно скомпилировано и связано с разделяемыми библиотеками, а объем ФЛЭШ-памяти сокращается, как и ожидалось.Разница с версией, которая связана со статическими библиотеками, заключается в том, что время запуска приложения примерно на 20 секунд больше, и я понятия не имею, почему.
Приложение работает на процессоре ARM9 с частотой 180 МГц и операционной системой Linux 2.6.17, 16 МБ ФЛЭШ-памяти (файловая система JFFS) и 32 МБ оперативной памяти.
Решение
Потому что общие библиотеки должны быть связаны во время выполнения, обычно с помощью dlopen() или чего-то подобного.Для статических библиотек такого шага нет.
Редактировать:еще несколько деталей.dlopen должен выполнять следующие задачи.
- Найдите общую библиотеку
- Загрузите его в память
- Рекурсивно загружать все зависимости (и их зависимости ....)
- Разрешить все символы
Для выполнения этого требуется довольно много операций ввода-вывода.
В статически связанной программе все вышеперечисленное выполняется во время компиляции, а не во время выполнения.Поэтому статически связанная программа загружается намного быстрее.
В вашем случае разница преувеличивается относительно медленным оборудованием, на котором должен выполняться ваш код.
Другие советы
Это прекрасный пример классического компромисса между скоростью и пространством.
Вы можете статически связать все свои исполняемые файлы, чтобы они работали быстрее, но тогда они будут занимать больше места
или
У вас могут быть общие библиотеки, которые занимают меньше места, но и больше времени на загрузку.
Так что решите, чем вы хотите пожертвовать.
Есть много факторов для этой разницы (операционная система, компилятор и т.д.), Но можно найти хороший список причин здесь.В основном разделяемые библиотеки были созданы из соображений экономии места, и большая часть "магии", необходимой для того, чтобы заставить их работать, снижает производительность.
(В качестве исторической заметки оригинальный Netscape navigator в Linux / Unix был статически связанным исполняемым файлом big fat).
Это может помочь другим с подобными проблемами:
Причина, по которой запуск в моем случае занял так много времени, заключалась в том, что настройка GCC по умолчанию - экспортировать все символы внутри библиотеки. Большим улучшением является установка параметра компилятора " -fvisibility = hidden ".
Все символы, которые должна экспортировать библиотека, должны быть дополнены оператором
__ attribute__ ((видимость (" по умолчанию ")))
см. gcc wiki
и очень хорошая статья как писать общие библиотеки
Хорошо, теперь я узнал, что использование общих библиотек имеет свои недостатки в отношении скорости. Я нашел эту статью о динамической компоновке и загрузке освещения. Процесс загрузки выглядит намного более длительным, чем я ожидал.
Интересно ... обычно время загрузки общей библиотеки незаметно в толстом приложении, которое статически связано. Поэтому я могу только предположить, что система либо очень медленно загружает библиотеку из флэш-памяти, либо загруженная библиотека проверяется каким-либо образом (например, приложения .NET запускают контрольную сумму для всех загруженных библиотек, значительно сокращая время запуска в некоторые случаи). Возможно, что совместно используемые библиотеки загружаются по мере необходимости и выгружаются впоследствии, что может указывать на проблему конфигурации. Р>
Итак, извините, я не могу не сказать почему, но я думаю, что это проблема с вашим устройством / ОС ARM. Вы пробовали вводить код запуска или статически связываться с 1 из наиболее часто используемых библиотек, чтобы увидеть, имеет ли это большое значение. Также поместите разделяемые библиотеки в тот же каталог, что и приложение, чтобы сократить время, необходимое для поиска в ФС библиотеки.
Один из вариантов, который мне кажется очевидным, - это статически связать несколько программ в один двоичный файл. Таким образом, вы продолжите делиться как можно большим количеством кода (возможно, больше, чем раньше), но вы также избежите накладных расходов динамического компоновщика и сэкономите место на наличии динамического компоновщика в системе.
Довольно легко объединить несколько исполняемых файлов в один, обычно вы просто проверяете argv и решаете, какую подпрограмму вызывать, основываясь на этом.