Библиотеки перезагружены на их предпочтительный адрес

На Windows Server 2003 мое приложение начало загружаться долго при новой установке. Подозреваю, что библиотеки DLL не загружаются по их предпочтительному адресу, и это занимает некоторое время (приложение имеет более 100 библиотек DLL, включая сторонних разработчиков). Я запустил утилиту sysinternals listDLLs, попросив ее пометить каждую DLL, которая была перемещена. Как ни странно, для большинства DLL-библиотек в списке я получаю что-то вроде этого:

Base        Size      Path
  ### Relocated from base of 0x44e90000:
0x44e90000  0x39000   validation.dll

То есть: они помечены как перемещенные (и время загрузки определенно поддерживает эту теорию), но их адрес загрузки остается предпочтительным адресом.

Некоторые сторонние библиотеки DLL, похоже, защищены от этого, но в целом это происходит с ~90% библиотек DLL, загружаемых приложением.

В Windows 7 может показаться, что единственными помеченными DLL являются те, которые действительно перемещаются, и время загрузки (как и ожидалось) значительно быстрее.

Чем это вызвано? Как я могу это остановить?

Отредактировано: так как это звучит (в теории) как эффекты ASLR, я проверил, и хотя библиотеки DLL OS действительно поддерживают ASLR, наши нет. И даже они перемещены на место, и, следовательно, не занимают адрес ни для одной из других DLL.

1 ответ

Это очень часто, настройка параметра компоновщика /BASE часто упускается из виду и поддержание его при росте DLL является неприятной задачей обслуживания. Это не очень хорошо повторяется между версиями операционной системы, они загружают разные библиотеки DLL впереди вашей, и это может привести к перемещению одной, но не другой. Также одиночное перемещение может вызвать последовательность принудительных перемещений во всех последующих DLL.

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

Гораздо более распространенная проблема во время загрузки - это скорость диска. Проблема, когда у вас много библиотек DLL, они должны быть расположены на диске при холодном запуске. С 100 DLL это может легко стоить 5 секунд. Вы должны подозревать проблему холодного запуска, когда вы не видите задержки, когда вы завершаете программу и запускаете ее снова. Это хороший старт, библиотеки DLL уже присутствуют в кеше файловой системы, поэтому их больше не нужно искать. Решение проблемы холодного старта требует лучшего оборудования, SSD - это хорошо. Или машина, изучающая ваш шаблон использования, поэтому SuperFetch предварительно запустит DLL-файлы для вас, прежде чем вы запустите программу.

В любом случае, если вы подозреваете проблему перебазирования, вам нужно создать свою собственную карту памяти, чтобы найти хорошие базовые адреса, которые не вызывают перемещение. Вам нужна хорошая отправная точка, зная порядок загрузки и размеры DLL. Вы получаете это, скажем, от отладчика VS. В окне "Вывод" отображается порядок загрузки, в окне "Отладка + модули Windows +" отображаются размеры DLL. Компоновщик поддерживает указание файла.txt для базовых адресов в параметре /BASE, лучший способ сделать это, чтобы вам не приходилось постоянно возиться с индивидуальным значением /BASE, пока ваш код продолжает расти.

Другие вопросы по тегам