是否可以将内存段标记为“超出范围”,以便堆管理员不从中分配?
-
28-09-2019 - |
题
今天早些时候我问 这个问题.
花了一些时间调查此问题后,我发现了正在发生的事情。我将其发布为一个新问题,因为我认为它足够有趣,可以作为单独的问题进行跟踪。我将通过答案更新该问题(以及指向该问题的链接)。
从调试器启动单元测试
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194 /* Different memory location */
从命令行启动单元测试
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960 /* Same memory location */
总之:
- 从 命令行, ,随后打电话给
new
分配一个Object
(delete
上一个Object
在分配新的之前)始终返回 相同的 记忆中的地址。 - 从 调试器, ,随后打电话给
new
分配一个Object
(delete
上一个Object
在分配新的之前)始终返回 独特 记忆中的地址。
问题是因为分配 Object
通过命令行启动时,始终在内存中获取相同的地址,我正在访问的地图存储了该地址 老的 指针仍然可以使用,测试不会崩溃。但是,我希望当缺陷修复设备时,我的设备测试崩溃了,以确保不会默默失败并且缺陷不会返回。
我的问题有2个部分:
为什么HEAP Manager在从命令行启动单元测试时重复使用同一部分,而不是从调试器启动单元测试时?
我可以在测试安全带上使用编译器设置,或者可以调用的方法以防止堆管理器重新使用我已删除的一部分内存,以使我正确编写单元测试? 1
1显然,这样做的一种方法是不要删除原始对象,但是分配此对象的一部分是在我的生产代码中,我这样做会导致内存泄漏。
解决方案
您的单位测试是有缺陷的,因为它依赖于未定义的行为。您应该重写单元测试,以免依赖不确定的行为,在这种情况下,无论内存管理器如何决定分配内存,它将始终通过。
您正在做的是:
Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed
相反,您应该重组单元测试,以便这样做:
Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it. If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests
其他提示
您可以替换 new
和 delete
带有您自己想要的行为的版本。
首先 - 不在“普通”内存管理器中。一旦您处理内存,就可以将其所有权传递给内存管理器,后者可以重复使用它。
你可以 写一个自定义经理 作为 用户Andreas Brinck 建议,但是它会做什么?它不会从空气中制作内存,而是从CRT堆或操作系统堆之类的某个地方请求它。
方案A.它不会将内存返回到基础堆 - 您将有一个泄漏,并且存储器块仍将映射到地址空间中,并且可以访问。
方案B.它将返回内存到基础堆 - 然后,当您的Mananger试图再次分配内存时,基础堆可以再次返回该块。另外,当您返回内存时,您不知道基础堆的作用。它可能会使它是否未映射 - 因此访问内存可能会崩溃。
最重要的是你被搞砸了。试图测试不确定的行为不会很有效。
这是不确定行为的一个例子。 C ++或HEAP Manager都没有定义如何分配内存。您不能依靠要重复使用或不重复使用的内存。当您做类似上述操作时,无法确定或更改返回的指针是否与第一个分配的指针不同。