Windows malloc替换(例如,tcmalloc)和动态crt链接

时间:2009-05-13 15:15:45

标签: windows dll malloc msvcrt crt

使用多个DLL和QT的C ++程序应该配备malloc替换(如tcmalloc),以解决可以验证由Windows malloc引起的性能问题。使用linux,没有问题,但是对于Windows,有几种方法,我发现它们都没有吸引力:

1。将新的malloc放入lib中,并确保首先将其链接(Other SO-question)

这有缺点,例如strdup will still use the old malloc and a free may crash the program

2。使用lib.exe(Chrome)

从静态libcrt库中删除malloc

这是chrome/chromium的测试/使用(?),但缺点是它只能与静态链接crt一起使用。如果一个系统库与msvcrt动态链接,则静态链接存在问题,可能存在mismatches in the heap allocation/deallocation。如果我理解正确,tcmalloc可以动态链接,以便所有自编译的dll都有一个公共堆(这很好)。

第3。补丁crt源代码(firefox)

Firefox's jemalloc显然修补了Windows CRT源代码并构建了一个新的crt。这再次出现了上面的静态/动态链接问题。

可以考虑使用它来生成动态MSVCRT,但我认为这是不可能的,因为许可证禁止提供具有相同名称的修补MSVCRT。

4。在运行时动态修补加载的CRT

一些商业内存分配器可以做到这一点。 tcmalloc也可以,但这看起来相当丑陋。它有一些问题,但它们已被修复。目前,使用tcmalloc它在64位窗口下不起作用。

有更好的方法吗?有什么意见吗?

4 个答案:

答案 0 :(得分:8)

问:一个分为几个dll的C ++程序应该:

A)替换malloc?

B)确保在同一个dll模块中进行分配和解除分配?

答:正确答案是B.包含多个DLL的c ++应用程序设计应该确保存在一种机制,以确保在一个dll中堆上分配的内容由同一个dll模块释放。< / p>


为什么要将c ++程序拆分成几个dll呢?通过c ++程序,我的意思是你正在处理的对象和类型是c ++模板,STL对象,类等。你不能通过dll边界传递c ++对象,而不需要很多非常仔细的设计和大量编译器特定的魔法,或者痛苦来自各个dll中大量重复的目标代码,因此对应用程序的版本非常敏感。对类定义的任何小改动都会强制重建所有exe和dll,从而消除了应用程序开发的dll方法的至少一个主要好处。

要么坚持应用程序和dll之间的直接C接口,要遭受痛苦,要么只是将整个c ++应用程序编译为一个exe。

答案 1 :(得分:5)

这是一个大胆的主张,C ++程序“应该配备malloc替换(如tcmalloc)以解决性能问题....”

  

“[In] 8个流行基准测试中的6个... [实际大小的应用程序]取代了自定义分配器,其中人们投入了大量的时间和金钱,......系统提供的哑配置器[产生]更好的性能....最简单的自定义分配器,针对非常特殊的情况进行调整,是唯一可以提供收益的分配器。“ - Andrei Alexandrescu

大多数系统分配器都与通用分配器一样好。如果你有一个非常具体的分配模式,你可以做得更好

通常,这种特殊模式仅适用于程序的一部分,在这种情况下,最好将自定义分配器应用于可以受益的特定部分,而不是全局替换分配器。

C ++提供了一些有选择地替换分配器的方法。例如,您可以为STL容器提供分配器,也可以逐个类地覆盖new和delete。这两种方法都比全局替换分配器的任何黑客都提供了更好的控制。

另请注意,替换malloc和free不一定会更改运算符new和delete使用的分配器。虽然全局新运算符通常使用malloc实现,但并不要求它这样做。因此,替换malloc可能甚至不会影响大多数分配。

如果您正在使用C,那么您可以使用自定义分配器将密钥malloc和免费调用包装或替换到其重要位置,并让程序的其余部分使用默认分配器。 (如果情况并非如此,您可能需要考虑进行一些重构。)

系统分配器背后有数十年的发展。它们稳定且经过充分测试。它们在一般情况下表现非常好(在原始速度,线程争用和碎片方面)。他们有调试版本用于泄漏检测和支持跟踪工具。有些甚至通过提供针对堆缓冲区溢出漏洞的防御来提高应用程序的安全性。有可能,您要使用的库仅使用系统分配器进行了测试。

替换系统分配器的大多数技术都会丧失这些优势。在某些情况下,它们甚至可以增加内存需求(因为它们不能与其他进程可能使用的DLL运行时共享)。面对编译器版本,运行时版本甚至操作系统版本的变化,它们也往往非常脆弱。使用运行时的调整版本可以防止用户从操作系统供应商那里获得运行时更新的好处。为什么要通过将自定义分配器应用于可以从中受益的程序的特殊部分来保留这些好处,从而完全解决这些问题?

答案 2 :(得分:1)

你的前提“使用多个DLL和QT的C ++程序应该配备malloc替换”来自哪里?

在Windows上,如果所有dll都使用共享MSVCRT,则无需替换malloc。默认情况下,Qt针对共享的MSVCRT dll构建。

如果他们出现问题:

1)混合使用静态链接的dll与使用共享VCRT

2) AND 还释放未分配的内存(即,由共享VCRT分配的静态链接dll中的空闲内存,反之亦然)。

请注意,在资源周围添加自己的ref计数包装器有助于缓解与需要以特定方式解除分配的资源相关的问题(即,通过回调到原始dll处理一种类型资源的包装器,一个源自另一个dll的资源的不同包装器等。)

答案 3 :(得分:1)

nedmalloc?另请注意,smplayer使用特殊补丁来覆盖malloc,这可能是您前进的方向。