Wei*_*nde 23 windows malloc dll crt msvcrt
使用多个DLL和QT的C++程序应该配备malloc替换(如tcmalloc),以解决可以验证由Windows malloc引起的性能问题.使用linux,没有问题,但是对于Windows,有几种方法,我发现它们都没有吸引力:
1.将新的malloc放入lib并确保首先链接它(其他SO问题)
这样做的缺点是,例如strdup仍将使用旧的malloc,而free可能会使程序崩溃.
2.使用lib.exe(Chrome)从静态libcrt库中删除malloc
对铬/铬进行测试/使用(?),但缺点是它只能与静态连接crt一起使用.如果一个系统库与msvcrt动态链接,则静态链接存在问题,堆分配/释放中可能存在不匹配.如果我理解正确,tcmalloc可以动态链接,以便所有自编译的dll都有一个公共堆(这很好).
3.补丁crt源代码(firefox)
Firefox的jemalloc显然修补了Windows CRT源代码并构建了一个新的crt.这又有上面的静态/动态链接问题.
人们可以考虑使用它来生成动态MSVCRT,但我认为这是不可能的,因为许可证禁止提供具有相同名称的修补MSVCRT.
4.在运行时动态修补加载的CRT
一些商业内存分配器可以做这样的魔术.tcmalloc也可以,但这看起来相当丑陋.它有一些问题,但它们已被修复.目前,使用tcmalloc它不能在64位窗口下工作.
有更好的方法吗?任何意见?
问:在几个dll中拆分的C++程序应该:
A)更换malloc?
B)确保在同一个dll模块中进行分配和解除分配?
答:正确答案是B. C++应用程序设计,采用多个DLL应保证的机制的存在是为了保证了在一个DLL在堆上分配的东西,用相同的DLL模块free'd.
为什么要将c ++程序拆分成几个dll呢?通过c ++程序,我的意思是你正在处理的对象和类型是c ++模板,STL对象,类等.你不能通过dll边界传递c ++对象,而不需要很多非常仔细的设计和大量编译器特定的魔法,或者痛苦来自各个dll中大量重复的目标代码,因此应用程序对版本非常敏感.对类定义的任何小改动都会强制重建所有exe和dll,从而消除了应用程序开发的dll方法的至少一个主要好处.
要么坚持应用程序和DLL之间的直接C接口,遭受地狱,或只是将整个c ++应用程序编译为一个exe.
这是一个大胆的主张,C++程序"应该配备malloc替换(如tcmalloc)以解决性能问题......"
"[在] 8个流行基准测试中的6个...... [实际大小的应用程序]取代了自定义分配器,其中人们投入了大量的时间和金钱,......系统提供的哑配置器[产生]更好的性能......最简单的自定义分配器,针对非常特殊的情况进行调整,是唯一可以提供增益的分配器." - 安德烈亚历山大夫斯库
大多数系统分配器与通用分配器一样好.只有在具有非常特定的分配模式时,才能做得更好.
通常,这种特殊模式仅适用于程序的一部分,在这种情况下,最好将自定义分配器应用于可以受益的特定部分,而不是全局替换分配器.
C++提供了一些有选择地替换分配器的方法.例如,您可以为STL容器提供分配器,也可以逐个类地覆盖new和delete.这两种方法都比全局替换分配器的任何黑客都提供了更好的控制.
另请注意,替换malloc和free不一定会更改运算符new和delete使用的分配器.虽然全局新运算符通常使用malloc实现,但并不要求它这样做.因此,替换malloc可能甚至不会影响大多数分配.
如果您正在使用C,那么您可以使用自定义分配器将密钥malloc和免费调用包装或替换到其重要位置,并使程序的其余部分使用默认分配器.(如果情况并非如此,您可能需要考虑进行一些重构.)
系统分配器背后有数十年的发展.它们稳定且经过充分测试.它们在一般情况下表现非常好(在原始速度,线程争用和碎片方面).他们有调试版本用于泄漏检测和支持跟踪工具.有些甚至通过提供针对堆缓冲区溢出漏洞的防御来提高应用程序的安全性.有可能,您要使用的库仅使用系统分配器进行了测试.
替换系统分配器的大多数技术都丧失了这些优点.在某些情况下,它们甚至可以增加内存需求(因为它们不能与其他进程可能使用的DLL运行时共享).面对编译器版本,运行时版本甚至操作系统版本的变化,它们也往往非常脆弱.使用运行时的调整版本可以防止用户从操作系统供应商那里获得运行时更新的好处.为什么要通过将自定义分配器应用于可以从中受益的程序的特殊部分来保留这些好处,从而提供所有这些功能?
你的前提“使用多个 DLL 和 QT 的 C++ 程序应该配备 malloc 替代品”从何而来?
在Windows上,如果所有dll都使用共享的MSVCRT,则无需替换malloc。默认情况下,Qt 针对共享的 MSVCRT dll 进行构建。
如果出现以下情况,就会遇到问题:
1) 混合使用静态链接与使用共享 VCRT 的 dll
2)并且还释放未在其来源处分配的内存(即,由共享 VCRT 分配的静态链接 dll 中的释放内存,反之亦然)。
请注意,在资源周围添加您自己的引用计数包装器可以帮助减轻与需要以特定方式释放的资源相关的问题(即,通过回调原始 dll 来处置一种类型的资源的包装器,一种不同的资源)。源自另一个 dll 等的资源的包装器)。