3

为什么这不会导致内存泄漏?我在堆上分配了 long long 的空间,然后将返回的指针更改为 char*。之后,我在这个指针上调用 delete(或者在第二个例子中是 free)。这两个示例似乎都不会导致内存泄漏。

#include <stdlib.h>

struct leaky {
   long long* testptr;
   leaky() {testptr = new long long; }
   ~leaky() { void* newptr = (void*) testptr;
              char* newptr2 = (char*) newptr;
              delete newptr2; }
};

struct leaky2 {
   long long* testptr;
   leaky2() { testptr = (long long*) malloc(sizeof(long long)); }
   ~leaky2() { void* newptr = (void*) testptr;
               char* newptr2 = (char*) newptr;
               free (newptr2); }
};

int main() {
   while (true) {
      {
         leaky leak = leaky();
      }
   }
}

我在 Unix 系统上测试了这个:gcc version 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC)。

4

4 回答 4

6

第一段代码是未定义的行为,因为您不能delete使用与您编辑的内容无关的类型new。第二种情况是正确的,所以我们可以讨论那个。

malloc和的接口free基于void*,因此类型在这里并不重要,但问题仍然存在:如何free知道分配了malloc多少?答案是它是实现定义的。它可以通过不同的方式来完成。分配器可以获取更大的内存块并将信息存储在该额外空间中。在某些情况下malloc,从不同的池中分配不同的固定大小(特别是对于小对象),因此不需要使用可能很小的对象来跟踪信息。在这些情况下,实现free只需要弄清楚内存来自哪个池并将块返回到池中。

于 2013-10-21T17:27:16.537 回答
4

malloc将一些簿记信息与它返回给您的地址的值相关联(有时在地址之前的内存区域中)。此簿记信息包含分配的大小。转换地址不会改变这个地址的值,只会改变你的代码对它的解释。

于 2013-10-21T17:21:06.113 回答
0
  1. 任何指向内存的指针都可以转换为 achar*并返回并具有相同的值。因此,转换为char*仅更改编译器解释值的方式(sizeof(*ptr)返回值等)。它不会改变指针的值。

  2. operator deletefree()接受一个void*. 因此,当要求任何一方释放内存时,无论如何“类型”的任何概念都已消失。他们必须能够解释这一点并在不知道这些字节曾经是什么的情况下使用内存。

    作为参考,他们通常通过分配一点额外内存并在地址返回给您之前以一些字节记录该内存的大小。但这是一个实现细节;不要依赖它。

于 2013-10-21T17:26:12.733 回答
0

当使用 malloc 或 new 时,使用的空间包括“开销”(与已用和空闲内存块的大小有关的信息,指向您需要的空间的实际指针)和“有效负载”(正在使用的内存)。

用于此簿记信息的一种行话形式是“初始化记录”,可能类似于以下结构

struct InitRecord
{
  int memBlockSize;
  void* mem;
};

这就是 malloc 记住你使用了多少内存的方式。进一步理解的一个好方法(也是一个有趣的练习!)是创建自己的堆分配器。

这里有很好的参考资料http://www.cs.ucsb.edu/~rich/class/cs170/labs/lab1.malloc/index.html

和这里

http://systematicgaming.wordpress.com/2008/08/05/memory-management-introduction/

于 2013-10-23T05:15:09.740 回答