【发布时间】:2022-10-22 00:21:29
【问题描述】:
众所周知,堆内存的释放必须使用与分配它的分配器相同的分配器。这是在跨 DLL 边界交换堆分配对象时要考虑的事情。
一种解决方案是为每个对象提供一个析构函数,就像在 C API 中一样:如果 DLL 允许创建对象 A,它必须提供一个函数 A_free 或类似的东西1.
另一个相关的解决方案是将所有分配包装到 shared_ptr 中,因为它们存储了指向释放器的链接2.
另一种解决方案是将顶级分配器“注入”到所有加载的 DLL 中(递归地)3.
另一种解决方案是不交换堆分配的对象,而是使用某种协议4.
另一个解决方案是绝对确保 DLL 将共享相同的堆,如果它们共享兼容的编译选项(编译器、标志、运行时等),这应该(将会?)发生56. 这似乎很难保证,特别是如果一个人想使用包管理器而不是一次构建所有东西。
有没有办法在运行时检查多个 DLL 之间的堆实际上是否相同,最好是跨平台的方式?
为了可靠性和易于调试,这似乎比希望应用程序立即崩溃而不是默默地破坏东西要好。
【问题讨论】:
-
您的解决方案#2根本没有解决方案。
shared_ptr没有单一的二进制兼容定义。 -
是的,我知道在 DLL 边界需要考虑两个要点:ABI 兼容性和“堆共享安全”。我的理解是具有“堆共享安全”意味着具有 ABI 兼容性,但倒数是错误的,您确认吗?
-
不,一点也不,你错过了对单一定义规则的遵守。您可以让两个 C++ 编译器共享相同的分配器(可能由 C 库提供),但使用不兼容的 C++ 标准库。更糟糕的是,
std::shared_ptr不是标准布局类,因此不同的 C++ 编译器看到相同的头文件会产生不同的二进制布局。
标签: c++ memory-management dll shared-libraries heap-memory