16

There are many questions on this website regarding freeing pointers after use and, further, setting them to NULL. Arguments are fierce and the topic is seemingly divided equally. For example: This question. I am confused about freeing pointers in general.

Imagine you have a pointer to some memory space. After using the space, you free the pointer but do not set it to NULL. Later, you have another pointer that calls malloc(), or some analog, and it is allocated memory including the memory freed earlier (that the original pointer still points to). If this new pointer writes in this memory block, what happens? Intuitively nothing would happen, but the OP in the link provided earlier writes that it would crash the program.


So my questions are:

  1. Given a freed pointer, what is keeping you from reassigning that pointer to a new memory location? Why is it 'bad' practice to reuse freed pointers? If calling free(ptr) only returns this memory to the OS, why can you not reassign the pointer so other memory locations and reuse it?

    char *ptr = malloc(sizeof(*ptr)); //first allocation
    free(ptr); //release memory 
    ptr = NULL; 
    ptr = malloc(sizeof(*ptr)); //reallocate
    
  2. Why would writing to a memory block that was previously freed, that still has the original pointer to it, cause the program to crash? -- See the first paragraph of the first post to the question linked above (if I misinterpreted the intent of this paragraph, please explain because it is not explicit whether that pointer is used again to write the memory or a new pointer is created.)

4

4 回答 4

15

给定一个已释放的指针,是什么阻止您将该指针重新分配到新的内存位置?

从技术上讲,什么都没有。您甚至不需要ptr = NULL在释放和重新分配指针之间进行设置。但是,当释放和重新分配由其他代码行分隔时,将指针设置为NULL可能会稍微提高可读性。

为什么写入之前释放的内存块,仍然有指向它的原始指针,导致程序崩溃?

只要您的程序不尝试取消引用该指针,只需持有指向可通过另一个指针访问的内存块的指针是绝对可以的。不幸的是,即使您取消引用已释放的指针,它也不一定会导致您的程序崩溃:通常情况下,这种行为会被忽视。但是,它仍然是一个未定义的行为。您的程序的另一部分可能写入的数据与您期望的不兼容,在这种情况下,您将看到极难发现或解释的错误。

于 2013-07-25T16:50:34.537 回答
4
  1. 由于原始指针现在再次指向分配的空间,因此可以使用它。但是,这样做是个坏主意;分配内存的代码认为它可以控制它,如果使用旧指针的代码修改了数据,它会感到不安。此外,新代码可能存储的数据类型与旧指针所期望的不同,因此使用旧指针的代码将无法理解发生了什么。

    在您的示例中,重用指针变量是没有问题的。第二个返回的值malloc()可能与第一个返回的值相同,或者可能不同,但是(即使没有分配 NULL)像这样重用指针也没问题(只要您随后释放第二个分配) .

  2. 如果空间被释放,则空间可能(尽管不太可能)未被操作系统映射,并且不再是程序可用的有效地址的一部分。与将空间返回给 O/S 相比,对数据含义的混淆更可能导致程序崩溃,但两者都有可能。

总结:不要使用旧的指针值来访问重新分配的内存——这会导致不愉快。

于 2013-07-25T16:48:34.937 回答
0

“为什么要写入先前释放的内存块,仍然具有指向它的原始指针,导致程序崩溃?-请参阅上面链接的问题的第一篇文章的第一段(如果我误解了这一段,请解释一下,因为它没有明确说明是否再次使用该指针写入内存或创建新指针。)"

我认为在释放后重用相同的内存空间等于'crime',至少对于基于 Kmem(slab 分配)的设计(我认为主要用于 linux ..如果我错了,请纠正我)。

要了解我们需要了解内部运作方式的原因(您可以跳过并阅读最后的结论):

  1. 操作系统将整个可动态分配的内存分成页面。这些页面中的每一个都被分配来保存对象(还有一些用于管理这些对象并将它们分页)。一页只能有一种内存大小的对象。例如,如果页面大小是 1024 字节,而页面将管理的对象是 32 字节。然后整个页面“可以”被划分为最多 1024/32 个对象。

在简单的嵌入式系统中,内存中的许多页面被划分为通常大小为 2^y 的对象(例如 8 字节、16 字节等)。因此,当您通过 malloc 请求 z 字节的内存时,其中

16 < z <=32

系统从保存在某些具有空闲对象的页面中的 32 字节对象池中返回一个对象。在为您分配此对象后,操作系统会更改“slab”数据结构并将给定地址处的对象标记为非空闲。

当您调用 free() 时,该对象作为空闲对象返回到平板池,如果发生其他 malloc 调用,操作系统可以重新分配它。此调用可以由您的代码或 os.sys 中运行的其他一些组件进行。

**因此,如果您重用操作系统先前分配给您的代码的已释放内存。然后您可能正在写入一些可能使用的内存位置:

  1. 通过您的代码或
  2. 操作系统中运行的其他一些组件**

此外,操作系统重新分配指针的其他一些组件也可能覆盖您的数据。

这可能会导致严重的数据损坏。

此外,请确保您不会向内存写入比您通过 malloc() 请求的数据更多的数据。这样做会导致:

  1. 其他一些组件数据被损坏
  2. 或者一些内存管理数据结构被破坏(如平板、缓存管理器等)。
于 2013-07-27T07:00:38.970 回答
-1

您没有正确使用该malloc()函数,请检查文档,这是正确的用法,因为它返回一个指针:

char *b;
b = (char *)malloc(42*sizeof(char));

sizeof()必须用于确定指针内容的大小(即char或其他),而不是指针本身的大小(除非您存储的是指针数组,而不是这里的情况)。

没有必要将释放的指针设置为 NULL,它只是没有任何意义。为释放的指针重新分配空间也没有问题,因为malloc()将返回指向内存块的指针,并且您将先前释放的指针分配给返回的指针 my malloc().

请注意,如果你想调整内存块的大小,有realloc().

于 2013-07-25T16:55:40.553 回答