不正确删除指针片段内存?

时间:2010-06-11 09:09:30

标签: c++ memory-leaks

这基本上就是问题。如果我有一个指针int *a = &someIntVar并且我不在程序过程中删除它,它会在程序终止后留在内存中吗?这是数据碎片的情况吗?

修改

我错误地使用了一个糟糕的例子。所以int *a = new int[100];永远不会被删除,即使它被删除,答案也会删除指针,而不是指针。然而指针也有一个长度。所以问题是,在Windows或Linux操作系统上,它会在指针后自动清理吗? (假设C ++)

6 个答案:

答案 0 :(得分:4)

由于你没有new这个指针,你没有泄漏内存。

如果你要int* a = new int;而不是delete a,那么你会泄漏a

根据经验,new的数量应等于delete的数量。

someIntVar超出范围时,堆栈被解开并且其内存将被释放,当然a将悬空。

答案 1 :(得分:4)

不,当进程终止时,通常会释放进程分配的所有内存。但是对于文件句柄或图形资源(例如在Win32设备上下文句柄,位图等)中的情况可能并非如此。

答案 2 :(得分:1)

关于delete p的一个令人困惑的事实是,它实际上并未删除p,而是*p。也就是说,你不删除指针,而是删除指针。每当您看到delete时,都应将其视为delete_what_is_pointed_to_by。哦是的,只有deletenew

答案 3 :(得分:1)

  

没有正确删除指针片段内存?

否。大量内存分配和释放会破坏内存。

这是对内存分配的直观解释(它比这更复杂,我的例子充其量是天真的,忽略了很多问题,但它应该为你提供一些想法)。

内存分配通常发生在(至少)两个步骤中:

  1. 操作系统为应用程序分配内存块。

  2. 应用程序从可用块中分配内存供自己使用。

  3. 如果应用程序使用了所有可用内存(或者它不能再分配),操作系统将为应用程序分配更多内存。这是透明地完成应用程序,但它需要时间(这就是内存分配缓慢的原因)。

    当应用程序释放内存时,地址/块被标记为空闲,并将在应用程序的后续分配请求(new / malloc / realloc / etc)上重用。

    当分配给应用程序的内存块变得碎片化时(某些片段被分配,一些片段空闲),就会发生内存碎片。

    例如:

    int *a = new int;
    int *b = new int;
    int *c = new int;
    int *d = new int;
    int *e = new int;
    int *f = new int;
    // if the memory blocks for the pointers were allocated contiguously,
    // the heap will look like this:
    // [ a ][ b ][ c ][ d ][ e ][ f ][ free memory ... ]
    
    // sometime later:
    delete b;
    delete d;
    delete e;
    // same memory block will look like this:
    // [ a ][free][ c ][free][free][ f ][ free memory ... ]
    

    为简单起见,假设您的应用程序以1000字节可用内存开头。如果在第一步中分配了200 int*(200个不同的变量),则分配200 x 4 = 800字节,200字节空闲。

    如果你想分配(第二步)new int[100]更多(一个指针,400多个字节),你将没有足够的可用内存,应用程序将不得不从操作系统请求更多。在当前块中至少需要200个字节,或者从操作系统中至少需要400个字节的新块。

    如果删除了在步骤1中分配的内存以在步骤2中分配空间,那么删除的内存将至关重要:

    • 如果您删除了最后分配的指针 - 您需要删除最后50个指针(50x4 = 200) - 您需要释放200个字节+ 200个未分配的指针= 400个需要)。的确定

    • 如果你删除了在步骤1中分配的每个第二个指针(或前50个指针)你有400个字节可用,但是碎片并且没有400个字节的连续内存可用。由于内存碎片,您在步骤2中的分配将失败。

      

    我错误地使用了一个糟糕的例子。所以int *a = new int[100];永远不会被删除,即使它被删除,答案也会删除指针,而不是指针。然而指针也有一定的长度。

    当你有int *a = new int[100];时,你有两个部分:

    • a(指针本身)的内存是4个字节(假设32位架构)在堆栈上分配。

    • a指向的内存为400字节,在堆上分配。

    当您致电delete[]a;时,将释放堆内存。当*超出范围时,堆栈存储器(用于指针本身)将被释放到可用的堆栈空间。

    您只需关注删除堆内存即可。根据程序本身的需要释放/重用堆栈存储器。

答案 4 :(得分:1)

int *a = new int[100];之后你使用sizeof(a) + sizeof(int[100])字节的内存。在delete a之后,您仍在使用sizeof(a)字节的内存。这是合乎逻辑的:您可以接下来写a = new int[50];a的内存仅在a本身超出范围时才会释放。如果a是全局的,那将是程序终止。

答案 5 :(得分:0)

在您使用的任何操作系统上试试这个:

  1. 首先观察进程内存占用量。在Linux中使用top,在Windows中使用任务管理器。
  2. 在int * p = new int [100000];
  3. 中分配100000的内存
  4. 观察进程的内存占用量。它必然会增加至少100k * 4字节。现在查看留给其他进程使用的“免费”内存。
  5. 让程序运行,不要删除任何内容。执行后,空间将返回到系统 - 您应该看到现在可用于其他程序的可用内存。
  6. 作为附注,不要假设如果你做删除[] p;在代码中间,您的100k * 4立即返回系统。这可能是也可能不是 - 例如Linux有自己的内存管理器来做出这样的决定。

    Arpan