Наш следующий продукт стал слишком большим для соединения на машине, запускающей 32-разрядный Windows. Суммарный итог всех библиотечных файлов превышает 2 ГБ и может только быть связан на 64-разрядной машине Windows. В конечном счете мы превысим ту границу, так как наше программное обеспечение имеет тенденцию расти, а не сокращаться, и мы используем 32-разрядного компоновщика (Visual Studio MS 2005): мы ожидаем поражать проблему, когда наше общее количество размера lib превысит 3 ГБ.
Как я могу уменьшить размер .lib файлов или .obj файлов, не обрезая код? Например, мы используем много шаблонов: есть ли какой-либо способ уменьшить их место? Есть ли какой-либо способ узнать то, что вызывает чрезмерное увеличение размера от исследования .lib/.obj файлов? Это может быть автоматизировано, а не осмотрено глазом? 2.5 ГБ являются большим количеством текста, чтобы взаимодействовать через и выдержать сравнение.
Внешние ограничения препятствуют тому, чтобы мы поставлялись как что-либо кроме единственного .exe, таким образом, решение DLL не доступно.
Попробуйте использовать программу Symbol Sort, которая покажет вам, где в вашем коде находятся основные биты раздутости. Также просто посмотрите на размер необработанных .obj-файлов - это даст вам разумное представление о том, куда направить усилия.
Однажды я работал над проектом с несколькими MLoC. В то время как наш по-прежнему будет связываться на 32-битной машине, время связывания было ужасным и стало серьезной проблемой, потому что разработчикам приходилось выполнять только дюжину циклов редактирования-компиляции-тестирования за рабочий день. (Время компиляции было довольно хорошо обработано за счет выполнения распределенной компиляции.)
Мы перешли на динамическое связывание. Это увеличило время запуска, но с этим можно было справиться, отложив загрузку библиотек DLL.
Во-первых, конечно, убедитесь, что вы компилируете с опцией «Оптимизировать по размеру». Если вы это сделаете, я бы не ожидал, что встраивание, по крайней мере, существенно повлияет на размер кода. Компилятор делает компромисс для каждого кандидата на встраивание относительно того, насколько (если вообще) он увеличит размер кода по сравнению с приростом производительности, который он дал. А если вы оптимизируете размер, компилятор не рискнет сильно раздуть код.(Обратите внимание, что встраивание очень маленьких функций может фактически уменьшить размер кода)
Во-вторых, рассматривали ли вы единую сборку ? Это в значительной степени полностью устранило бы компоновщик, и только с одной единицей перевода было бы намного меньше дублирующей работы и, надеюсь, меньше занимаемой памяти.
Наконец, я знаю, что Visual Studio (или, возможно, Windows SDK) имеет 64-битный компилятор (то есть компилятор, который сам является 64-битным приложением, а не просто компилятором, производящим 64-битный код). Подумайте об использовании этого. (Я не знаю, существует ли еще 64-битный компоновщик)
Я не знаю, что компоновщик построен с установленным флагом LARGEADDRESSAWARE. Если это так, запуск его на 64-битной машине позволит процессу использовать полные 4 ГБ памяти вместо 2 ГБ, которые он обычно получает. (при необходимости вы можете добавить флаг самостоятельно, изменив заголовок PE)
Возможно, также может помочь ограничение связывания различных символов. Если вы знаете, что символ не понадобится за пределами текущей единицы перевода, поместите его в анонимное пространство имен. Это может позволить компилятору обрезать неиспользуемые символы перед передачей всего компоновщику
OMFG !!!!! Это ууууууге!
Помимо того факта, что я считаю его слишком большим, чтобы быть рациональным ... разве вы не можете использовать динамическое связывание, чтобы не связывать весь беспорядок во время компиляции, и связывать только то, что необходимо во время выполнения (я имею в виду загрузку dll по запросу) ?
Это должно быть одно большое приложение?
Один из вариантов - разделить различные модули на библиотеки DLL и загрузить / выгрузить их по мере необходимости.
В качестве альтернативы вы можете разделить на несколько приложений и обмениваться данными с использованием отображаемой памяти, конвейера СУБД или даже простых файлов данных.
Прежде всего, выясните, как измерить размер, который используется различными функциями. Не пытайтесь играть с заменой использования шаблонов или другими вещами, потому что вы подозреваете, что это имеет существенное значение.
Выполните
dumpbin /HEADERS <somebinary>
, чтобы выяснить, какие разделы в вашем бинарном файле вызывают огромный размер. Есть ли у вас огромный раздел Debug Directory? Удалите символы. Велика ли таблица адресов импорта? Проверьте таблицу и найдите ненужные символы (проблема с шаблонами заключается в том, что символы инстанций шаблонов имеют тенденцию быть очень большими). Аналогичный анализ можно провести для каталога исключений, каталога дескрипторов COM и т.д..
Я не думаю, что существует какой-то один инструмент, который может дать вам статистику, которая вам нужна. Использование файлов .map или утилиты dumpbin
с параметром /SYMBOLS
плюс некоторая постобработка созданного журнала может помочь вам получить то, что вы хотите.
Если статистика подтвердит ваши подозрения о раздутости шаблонов, или даже без подтверждения, возможно, будет хорошей идеей сделать несколько вещей с исходниками:
Я очень скептически отношусь к тому, что ваш реальный код составляет 2 ГБ; скорее всего, вы собираете много информации. Рассмотрите возможность выгрузки части этой информации в файл ресурсов и встраивания ее в исполняемый файл в качестве отдельного шага.