Замена malloc в Windows (например, tcmalloc) и динамическое связывание crt - PullRequest
23 голосов
/ 13 мая 2009

Программа на C ++, использующая несколько библиотек DLL и QT, должна быть оснащена заменой malloc (например, tcmalloc ) для проблем с производительностью, которые могут быть проверены как вызываемые Windows malloc. С linux проблем нет, но с windows есть несколько подходов, и я не нахожу ни одного из них привлекательным:

1. Поместите новый malloc в lib и убедитесь, что он сначала связан с ним (Другой вопрос SO)

Это имеет тот недостаток, что, например, strdup будет по-прежнему использовать старый malloc, и free может привести к сбою программы .

2. Удалите malloc из статической библиотеки libcrt с помощью lib.exe (Chrome)

Это проверено / используется (?) Для хром / хром , но имеет тот недостаток, что он работает только со статическим связыванием эл. Статическое связывание имеет проблему, если одна системная библиотека динамически связана с msvcrt, могут быть несоответствия в распределении / освобождении кучи . Если я правильно понимаю, tcmalloc мог бы быть связан динамически, так что есть общая куча для всех скомпилированных dll (что хорошо).

3. Патч crt-исходный код (firefox)

jemalloc Firefox , по-видимому, исправляет исходный код Windows CRT и создает новый crt. Это снова имеет проблему статического / динамического связывания выше.

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

4. Динамическое исправление загруженной ЭЛТ во время выполнения

Некоторые коммерческие распределители памяти могут творить такое волшебство. tcmalloc тоже может это сделать, но это выглядит довольно уродливо. У него были некоторые проблемы, но они были исправлены. В настоящее время tcmalloc не работает под 64-битными окнами.

Есть ли лучшие подходы? Есть комментарии?

Ответы [ 4 ]

8 голосов
/ 19 мая 2009

В: Программа на C ++, разделенная на несколько библиотек, должна:

A) заменить malloc?

B) гарантировать, что распределение и перераспределение происходит в одном и том же модуле DLL?

A: Правильный ответ: B. Проект приложения c ++, который включает в себя несколько библиотек DLL, ДОЛЖЕН гарантировать, что существует механизм, гарантирующий, что вещи, размещенные в куче в одной dll, будут свободны для одного и того же модуля dll.


Зачем вам в любом случае разбивать программу на С ++ на несколько библиотек? Под программой на С ++ я имею в виду, что объектами и типами, с которыми вы имеете дело, являются шаблоны с ++, объекты STL, классы и т. Д. Вы НЕ МОЖЕТЕ передавать объекты с ++ через границы DLL без большого количества очень тщательного проектирования и большого количества магии, специфичной для компилятора, или страданий. из-за массового дублирования объектного кода в различных библиотеках и, как следствие, приложения, которое чрезвычайно чувствительно к версии. Любое небольшое изменение в определении класса вынудит перестроить все exe и dll, удалив хотя бы одно из основных преимуществ dll подхода к разработке приложений.

Либо придерживайтесь прямого интерфейса C между приложением и dll, перенесите ад, либо просто скомпилируйте все приложение c ++ как один exe.

5 голосов
/ 10 сентября 2011

Это смелое утверждение, что программа C ++ "должна быть оснащена заменой malloc (например, tcmalloc) для проблем с производительностью ...."

"[In] 6 из 8 популярных эталонных тестов ... [приложения реального размера] заменяют пользовательский распределитель, в который люди вложили значительные суммы времени и денег, ... на предоставляемый системой тупой распределитель [уступил] лучшая производительность. ... Простые пользовательские распределители, настроенные для очень особых ситуаций, являются единственными, которые могут обеспечить выигрыш ". - Андрей Александреску

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

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

C ++ предоставляет несколько способов выборочной замены распределителя. Например, вы можете предоставить распределитель для контейнера STL или вы можете переопределить новый и удалить для каждого класса в отдельности. Оба из них дают вам гораздо лучший контроль, чем любой хак, который глобально заменяет распределитель.

Обратите внимание, что замена malloc и free не обязательно изменит распределитель, используемый операторами new и delete. Хотя глобальный новый оператор обычно реализуется с помощью malloc, требования к нему отсутствуют. Поэтому замена malloc может даже не повлиять на большинство выделений.

Если вы используете C, скорее всего, вы можете обернуть или заменить ключ malloc и бесплатные вызовы своим пользовательским распределителем именно там, где это важно, и оставить оставшуюся часть программы, чтобы использовать распределитель по умолчанию. (Если это не так, вы можете рассмотреть возможность рефакторинга.)

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

Большинство методов замены системного распределителя лишены этих преимуществ. В некоторых случаях они могут даже увеличить потребность в памяти (поскольку они не могут использоваться совместно со средой выполнения DLL, возможно, используемой другими процессами). Они также имеют тенденцию быть чрезвычайно хрупкими перед лицом изменений в версии компилятора, времени выполнения и даже версии ОС. Использование измененной версии среды выполнения не позволяет вашим пользователям получать преимущества обновлений среды выполнения от поставщика ОС. Зачем отказываться от всего этого, если вы можете сохранить эти преимущества, применяя специальный распределитель только к той исключительной части программы, которая может извлечь из этого пользу?

1 голос
/ 20 мая 2009

nedmalloc? Также отметим, что smplayer использует специальный патч для переопределения malloc, который может быть направлением, в котором вы движетесь.

1 голос
/ 16 мая 2009

Откуда берется ваша посылка "Программа на C ++, которая использует несколько DLL и QT должна быть оснащена заменой malloc"?

В Windows, если все библиотеки используют общий MSVCRT, нет необходимости заменять malloc. По умолчанию Qt собирается против общей библиотеки MSVCRT.

Проблемы могут возникнуть, если они:

1) микс dll, использующие статическое связывание, и общий VCRT

2) И также свободная память, которая не была выделена, откуда она взялась (т. Е. Свободная память в статически связанной DLL, которая была выделена общим VCRT или наоборот).

Обратите внимание, что добавление вашей собственной оболочки с подсчетом ссылок вокруг ресурса может помочь уменьшить проблемы, связанные с ресурсами, которые необходимо освободить определенным образом (т. Е. Оболочкой, которая избавляется от одного типа ресурса посредством обратного вызова к исходной DLL другая оболочка для ресурса, который происходит из другой библиотеки и т. д.).

...