24

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

1.将新的malloc放入lib并确保首先链接它(其他SO问题)

这有一个缺点,例如strdup 仍将使用旧的 malloc 并且 free 可能会使程序崩溃

2. 使用 lib.exe (Chrome) 从静态 libcrt 库中删除 malloc

这已针对chrome/chromium进行了测试/使用(?),但缺点是它仅适用于静态链接 crt。如果一个系统库与 msvcrt 动态链接,则静态链接会出现问题,堆分配/释放中可能存在不匹配。如果我理解正确,tcmalloc 可以动态链接,这样所有自编译的 dll 都有一个公共堆(这很好)。

3.补丁crt-源码(firefox)

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

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

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

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

有更好的方法吗?任何意见?

4

4 回答 4

8

问:跨多个 dll 拆分的 C++ 程序应该:

A)替换malloc?

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

答:正确答案是 B。包含多个 DLL 的 c++ 应用程序设计应该确保存在一种机制,以确保在一个 dll 中的堆上分配的东西被同一个 dll 模块释放。


你为什么要把一个 c++ 程序分成几个 dll 呢?通过 c++ 程序,我的意思是您正在处理的对象和类型是 c++ 模板、STL 对象、类等。如果没有大量非常仔细的设计和大量编译器特定的魔法,或者遭受痛苦,您就无法跨 dll 边界传递 c++ 对象由于各种 dll 中目标代码的大量重复,因此应用程序对版本非常敏感。对类定义的任何微小更改都将强制重新构建所有 exe 和 dll,从而消除 dll 方法对应用程序开发的至少一个主要好处。

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

于 2009-05-19T12:23:24.850 回答
6

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

“[在] 8 个流行基准测试中的 6 个……[实际大小的应用程序] 替换了人们在其中投入了大量时间和金钱的自定义分配器,……使用系统提供的哑分配器 [yielded]更好的性能......最简单的自定义分配器,针对非常特殊的情况进行调整,是唯一可以提供收益的分配器。” ——安德烈·亚历山德雷斯库

大多数系统分配器与通用分配器差不多。只有当你有一个非常具体的分配模式时,你才能做得更好。

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

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

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

如果您使用的是 C,您可以在重要的地方使用自定义分配器包装或替换密钥 malloc 和 free 调用,并让程序的其余部分使用默认分配器。(如果不是这种情况,您可能需要考虑进行一些重构。)

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

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

于 2011-09-09T23:36:54.340 回答
1

您的前提“使用多个 DLL 和 QT 的 C++ 程序应配备 malloc 替代品”从何而来?

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

如果他们:

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

2)以及未在其来源处分配的空闲内存(即,由共享VCRT分配的静态链接 dll 中的空闲内存,反之亦然)。

请注意,在资源周围添加您自己的引用计数包装器可以帮助缓解与需要以特定方式释放的资源相关的问题(即,通过回调原始 dll 来处理一种类型资源的包装器,不同的来自另一个 dll 的资源的包装器等)。

于 2009-05-16T02:51:15.710 回答
1

内德马洛克?还要注意 smplayer 使用一个特殊的补丁来覆盖 malloc,这可能是你前进的方向。

于 2009-05-20T12:24:06.573 回答