【发布时间】:2018-01-29 23:34:43
【问题描述】:
正确链接的 DLL 和 EXE 应该有一个空闲存储区,它们都可以从中分配基于堆的对象。这是 Chis Becke 在Who allocates heap to a DLL? 中的回答:
…C++ 运行时负责创建它的 freestore 并决定 如何分配它。 具体来说,如果您使用 Dll 运行时选项,则单个 dll - msvcrtxx.dll - 管理单个 在所有 dll 和 exe 之间共享的 freestore,这些 dll 链接到该 dll
既然这是真的,那么我应该能够在其他 DLL/EXE 中定义的 DLL/EXE 中的 new 对象。根据 Chris 的说法,msvcrtxx.dll 和编译时/运行时链接器负责获取所有 DLL/EXE 的联合免费存储区。
这对我不起作用。
为了测试这一点,我生成了两个 MFC 对话框程序:NewFailMfc1 和 NewFailMfc2。在执行new 时,运行访问NewFailMfc1 的Www 函数的NewFailMfc2 失败。
// Code in NewFailMfc1.
void Www()
{
char* ch { nullptr };
ch = new char[ 100 ]; // error: attempts to allocate memory somewhere else than in the prescribed joint DLL/EXE freestore
ch[ 0 ] = '\0';
}
// Calling code in NewFailMfc2.
Www();
有比我更了解 DLL/EXE freestore 工作原理的人知道问题出在哪里吗?
(我之前曾尝试在“全局函数::operator new在MyApp1和MyApp2编译时失败。在询问过程中,我发现问题比@987654335更普遍地发生@标准库。)
编辑1:
在 MSDN 中,一个不错的虚拟代理为我找到了 Potential Errors Passing CRT Objects Across DLL Boundaries。不幸的是,它推荐的唯一解决方案是使用/MD 编译器选项编译所有程序,而不是/MT,它使用CRT 的多个副本,这会自动导致越界 和内存访问冲突。
对于像我这样的应用开发者来说,这可不是什么好消息。我需要的是一个最佳实践,这样我就可以应用它并满足我的交付期限,而不必处理神秘的低级内存问题。我怎么知道std:random_device 类型中有一个对全局::operator new 的隐藏调用?我不会,直到它违反访问权限。直到现在,在所有这些研究之后,我才意识到,通过调用全局 new,它跨越了边界,这给了我的 DLL/EXE 访问冲突。非常晦涩。
EDIT2:
我已经在 Visual Studio 中提交了一份关于 std::random_device 实现的错误报告。请参阅“std::random_device 实例化在某些情况下会导致访问冲突”。
【问题讨论】:
-
“根据 Chris 的说法,msvcrtxx.dll 和编译时/运行时链接器负责获取所有 DLL/EXE 的联合 freestore。” ——他不是这么说的,也不是真的。
-
这是过时的信息,自 VS2012 以来就不是这样了。以前,是的。您必须确保使用完全相同的设置使用完全相同的 VS 版本构建所有模块。可以像使用 dll 的发布版本来调试 exe 一样简单。确保所有项目都在同一个解决方案中,以便它们都可以使用相同的设置。
-
我相信 Hans 是正确的——通常我保持一个经验法则,即每个模块分配和处理它自己的内存,因为以这种方式在进程之间共享内存比它应该做的工作要多得多。至少在不使用内置规定的情况下这样做——不确定 Windows 是否像 Linux 那样容易公开。
-
@Hans Passant 我知道所有参与的 DLL 和 EXE 必须是相同的版本。我在 MSDN 中找到了一篇文章,解释了使用堆对象跨越 DLL/EXE 边界的危险。
-
“我需要的是一个最佳实践,这样我就可以应用它并满足我的交付期限,而不必处理神秘的低级内存问题”你一定是原生编程新手。
标签: c++ dll exe new-operator heap-memory