内存泄漏的长期后果是什么?

时间:2014-01-19 18:49:40

标签: c++ memory

假设我有一个这样的程序:

int main(void)
{
    int* arr = new int[x];
    //processing; neglect to call delete[]
    return 0;
}

在这样一个简单的例子中,我假设忽略释放为arr分配的内存几乎没有实际的危害,因为它应该在程序运行完毕后由OS释放。但是,对于任何非平凡的程序,这被认为是不好的做法,并会导致内存泄漏。

我的问题是,在一个非平凡的程序中,内存泄漏的后果是什么?我意识到内存泄漏是不好的做法,但我不明白为什么它们是坏的,它们导致的麻烦。

6 个答案:

答案 0 :(得分:13)

内存泄漏可能会通过减少可用内存量来降低计算机的性能。最终,在最坏的情况下,可能会分配太多的可用内存,并且系统或设备的全部或部分停止正常工作,应用程序失败,或者系统由于颠簸而无法接受地降低速度。

通过正常方式,内存泄漏可能不严重甚至无法检测到。在现代操作系统中,应用程序使用的正常内存在应用程序终止时释放。这意味着程序中只能运行一小段时间的内存泄漏可能不会被注意到并且很少发生严重。

更严重的泄漏包括:

  • 程序运行的时间较长,并且会随着时间的推移消耗额外的内存,例如服务器上的后台任务,尤其是可能会运行多年的嵌入式设备
  • 为一次性任务频繁分配新内存,例如渲染计算机游戏或动画视频的帧时
  • 即使程序终止,程序也可以请求未释放的内存(如共享内存)
  • 其中内存非常有限,例如在嵌入式系统或便携式设备中
  • 操作系统或内存管理器中发生泄漏的情况
  • 当系统设备驱动程序导致泄漏时
  • 在程序终止时不会自动释放内存的操作系统上运行。通常在这样的机器上,如果内存丢失,它只能通过重启来回收,这种系统的一个例子是AmigaOS。

查看here了解详情。

答案 1 :(得分:4)

您的问题有一个潜在的假设:

  

deletedelete[]的角色完全来释放记忆。

......这是错误的。

无论好坏,deletedelete[]都有双重角色:

  1. 运行析构函数
  2. 可用内存(通过调用operator delete的正确重载)
  3. 通过更正的假设,我们现在可以提出更正的问题:

      

    不调用delete / delete[]来结束动态分配变量的生命周期有什么风险?

    如上所述,明显的风险是泄漏内存(并最终崩溃)。然而,这是你最不担心的事情。更大的风险是未定义的行为,这意味着:

    • 编译器可能无意中不会产生行为符合预期的可执行代码: Garbage in,Garbage out
    • 用实用的术语来说,最可能的输出是析构函数不会运行......

    后者非常令人担忧:

    • Mutexes :忘记释放锁定,让你陷入僵局......
    • 文件描述符:某些平台(例如我相信的FreeBSD)对进程可能打开的文件描述符数量的默认限制非常低;无法关闭文件描述符,您将无法打开任何新文件或套接字!
    • 套接字:作为文件描述符,有一个与IP相关的有限范围的端口(最新版本的Linux不再是全局的,是的!)。绝对最大值为65,536(u16 ...),但短暂的端口范围通常要小得多(一半)。如果您忘记及时释放连接,您很容易就会遇到这样的情况,即使您有足够的可用带宽,您的服务器也会停止接受新的连接,因为没有可用的临时端口。
    • ...

    的态度问题,无论如何我有足够的内存,因为内存可能是最少的,因此内存可能是你最不担心的您操纵的稀缺资源

    当然你可以说:好吧,我会集中精力处理其他资源泄漏,但现在工具会将它们报告为内存泄漏(这已经足够了),因此隔离数百/数千的泄漏就像在大海捞针寻找针......

    注意:我是否提到你仍然可能内存不足?无论是在低端机器/系统上还是在受限制的进程/虚拟机上,内存的任务都非常紧张。

    注意:如果您发现自己正在调用delete,那么您做错了。学习使用标准库std::unique_ptr及其容器std::vector。在C ++中,自动内存管理很容易,真正的挑战是避免悬空指针......

答案 2 :(得分:2)

假设我们正在运行此程序:

while(true)
{
    int* arr = new int;
}

短期问题是您的计算机最终会耗尽内存,程序将崩溃。

相反,我们可以让这个程序永远运行,因为没有内存泄漏:

while(true)
{
    int* arr = new int;
    delete arr;
}

当像这样的简单程序崩溃时,没有长期后果,因为操作系统会在崩溃后释放内存。

但是你可以想象一下系统崩溃会带来灾难性后果的更关键系统,例如:

while(true)
{
    int* arr = new int;
    generateOxygenForAstronauts();
}

想想宇航员并释放你的记忆!

答案 3 :(得分:0)

运行一小段时间然后退出的工具通常可以避免内存泄漏,如您的示例所示。但是,预计长时间无故障运行的程序必须完全没有内存泄漏。正如其他人所说,整个系统将首先陷入困境。此外,泄漏内存的代码通常在处理分配失败时非常糟糕 - 分配失败的结果通常是崩溃和数据丢失。从用户的角度来看,这种崩溃通常发生在最糟糕的时刻(例如在文件保存期间,文件缓冲区被分配时)。

答案 4 :(得分:0)

嗯,这是一个奇怪的问题,因为直接的答案是直截了当的:当你丢失内存泄漏的内存时,你可能/最终会耗尽内存。对特定程序来说代表的问题有多大取决于每个泄漏的大小,这些泄漏发生的频率以及持续时间。这里的所有都是它的。

分配相对较少的内存和/或不连续运行的程序可能不会因内存泄漏而受到任何问题。但是一个连续运行的程序最终会耗尽内存,即使它非常缓慢地泄漏。

现在,如果一个人决定仔细观察它,那么每个内存块都有两面:它占据进程地址空间中的一个地址区域,它占用了实际物理存储的一部分。

在没有虚拟内存的平台上,双方都对你不利。一旦内存块泄露,您将丢失地址空间并丢失存储空间。

在具有虚拟内存的平台上,实际存储实际上是无限的资源。你可以根据需要泄漏尽可能多的内存,你永远不会用完实际的存储空间(当然在几乎合理的范围内)。泄漏的内存块最终会被推送到外部存储器并被遗忘,因此它不会以任何负面方式直接影响程序。但是,它仍将保留其地址空间区域。地址空间仍然是一个有限的资源,你可以用完。

可以说,如果我们采用一个假想的虚拟内存平台,其地址空间比我们的进程(例如,2048位平台和典型的文本编辑器)所能消耗的任何东西都要大得多,那么内存泄漏将没有我们的计划的后果。但在现实生活中,内存泄漏通常构成严重问题。

答案 5 :(得分:-1)

现在编译器在生成二进制文件之前对代码进行了一些优化。因此,单个新版本不会删除它就不会有太大的危害。

但一般来说,通过执行任何“Newing”,您应该“删除”您在程序中保留的那部分内存。

并且还要注意,简单删除并不能保证内存不足。 O.S.有不同的方面。和编译器端控制此功能。

This link may help you a little And this one too