1

我有一个疑问:

void *a = malloc(40);
free(a);

如果我认为 malloc(40) 分配了 40 个字节的内存并返回该内存的地址,然后 free(a) 释放/释放该内存,但对该内存中的位模式不做任何事情。所以,假设这个相同的内存被分配给说 void *b,然后在打印 b 指向的地址处的值时,给了我相同的值,或者它给了我一个垃圾值,为什么?

4

7 回答 7

5

我假设您有这种情况:

void * a = malloc(40);
free(a);
void * b = malloc(40);

assert(a == b);

这当然是完全合理的,因为内存可能会被重用。

但是,由于a == b,您已经回答了自己的问题: 的值b与 的值相同a

我相信您问错了问题,并且您实际上比较b. 那是一锅完全不同的鱼。malloc两次通话之间可能发生任何事情。没有什么是保证的。malloc调用的返回值指向的内存是未初始化的,你不能对其内容做任何假设。按理说,在典型的优化 C 库中内存不会发生变化,但不能保证。“安全”运行时环境可能会选择使用特定的测试模式覆盖已释放或分配的内存,以便更好地检测无效访问。

于 2012-09-26T11:55:05.857 回答
3

它可以给你任何价值。
C/C++ 标准不要求值是任何特定的。用技术术语来说,任何未初始化的变量/内存的值都是Indeterminate

简而言之,你的程序不应该依赖这个值来做任何特定的事情,如果是,那么它是不可移植的。

于 2012-09-26T11:50:25.700 回答
0

它不能保证任何事情。从malloc获得的打印块可能会打印以前的数据,也可能不会。有很多事情可以改变下一个 malloc 块(所以下一个地址会不同)或改变旧的内存块本身。

于 2012-09-26T11:56:15.247 回答
0

free 通常会修改你正在释放的内存。

这是一个常见的技巧,尤其是在调试模式下,可以使用一些固定模式免费覆盖内存,以便更容易判断您是在双重释放内存,还是只是在操作释放的内存。

同样 malloc 可能会用不同的模式覆盖内存,以使内存明显未初始化。

于 2012-09-26T11:57:19.910 回答
0

malloc 和 free 是 C 风格的内存管理,而不是 C++。C++ 的替代品是 new 和 delete 运算符。至于 free() 后内存中剩余的位模式,是的,它是相同的位模式。如果要手动删除位模式,可以在编写 WinApi 代码时使用 memset() 或 ZeroMemory()。

于 2012-09-26T11:57:20.947 回答
0

它将为您提供一些垃圾值,因为函数free()会将指定的字节设置为某种模式,这将使内存知道这些字节已被释放和未初始化。话虽如此,您将遇到问题中定义的案例的可能性很小且极不可能。即使您将再次获得相同的字节,相信我,您也不会认出它们 :-)

AFAIK,free()通常使用 Visual Studio 将内存设置为 0xFE 0xEE,这大致意味着内存已分配但现在已释放。这些值称为Sentinel Values,这意味着堆仍归进程所有,但未在使用中。从进程中释放的内存将显示“?? ??” .

于 2012-09-26T12:19:20.657 回答
-1

首先,代码不是 c++,而是纯 c。

原因是free()/delete存在于那里,因此系统可以注意到内存区域再次可用于分配。

它为什么要超越它?

然而,这是一个安全问题。我相信一些面向安全的现代系统在将内存分配给应用程序之前会将其归零。然后,如果您第一次使用,您将获得与callocmalloc()等效的。无论如何,如果您碰巧释放内存然后再次分配它可能能够读取您自己的数据。

这种行为的原因很简单。将内存归零会很耗时,您可以手动完成。实际上它有O(n)复杂性。如果您编写了一个重用其内存的数字运算器,那么您并不关心之后会得到什么,malloc()因为您很可能应该覆盖它,并且您绝对不希望您的 FLOPSmemset()在调用时受到不必要的负面影响free()

如果你想确保在你调用之后没有任何东西可以读取内存,free你需要memset(a, 0, SIZE)在调用之前使用free()

于 2012-09-26T12:01:46.840 回答