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

What are the long term consequences of memory leaks?

本文关键字:后果 是什么 泄漏 内存      更新时间:2023-10-16

假设我有这样的程序:

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

在这样的微不足道的示例中,我认为忽略释放为arr分配的内存的实际危害几乎没有,因为当程序完成运行时,OS应将其释放。但是,对于任何非平凡的程序,这被认为是不良习惯,并且会导致内存泄漏。

我的问题是,非平凡程序中内存泄漏的后果是什么?我意识到内存泄漏是不良的练习,但是我不明白为什么他们很糟糕, 他们造成的麻烦。

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

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

更严重的泄漏包括:

  • 该程序会长时间运行并随着时间的推移而消耗其他内存,例如服务器上的背景任务,但尤其是在嵌入式设备中运行多年的嵌入式设备
  • 经常为一次性任务分配新内存的地方,例如呈现计算机游戏的帧或动画视频
  • 程序可以请求内存(例如共享内存)的地方,即使程序终止
  • ,也不会发布。
  • 在内存非常有限的地方,例如在嵌入式系统或便携式设备中
  • 在操作系统或内存管理器内发生泄漏的地方
  • 当系统设备驱动器导致泄漏
  • 在无法在程序终止上自动释放内存的操作系统上运行。通常在此类机器上,如果存储器丢失,则只能通过重新启动来收回,这是Amigaos的一个例子。

在此处查看以获取更多信息。

您的问题有一个基本假设:

deletedelete[]的作用是纯粹释放内存。

...这是错误的。

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

  1. 运行破坏者
  2. 免费内存(通过调用operator delete的正确过载)

有了更正的假设,我们现在可以提出校正的问题:

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

如前所述,明显的风险是泄漏内存(最终崩溃)。但是,这是您最少的担忧。更大的风险是不确定的行为,这意味着:

  • 编译器可能会无意间产生可执行的代码,该代码行为预期:垃圾中,垃圾输出
  • 用务实的话来说,最有可能的输出是毁灭者不运行...

后者非常令人担忧:

  • 静音:忘记释放锁,您会陷入僵局...
  • 文件描述符:某些平台(我相信FreeBSD)臭名昭著的对一个过程可能打开的文件描述符数量的默认限制较低;无法关闭文件描述符,您将无法打开任何新文件或套接字!
  • 插座:在作为文件描述符的基础上,与IP关联的端口范围有限(最新版本的Linux不再是全局,是的!)。绝对最大值为65,536(U16 ...),但短暂的端口范围通常要小得多(一半)。如果您忘记及时发布连接,您可以在某种情况下轻松地最终出现,即使您有大量的带宽,您的服务器也会停止接受新连接,因为没有短暂的端口。
  • ...

的态度的问题,我有足够的记忆是,内存可能是您最少的担忧,仅仅是因为记忆可能是至少是您操纵的稀缺资源

当然可以说:好吧,我将专注于其他资源泄漏,但是如今的工具将其报告为记忆泄漏(而且还足够),因此隔离,数百/千的泄漏就像在干草堆中寻求针...

注意:我是否提到您仍然可以用完存储器?无论是在低端机器/系统上还是在限制过程/虚拟机器上的内存中,对于手头的任务都可能很紧。

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

,假设我们让这个程序运行:

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

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

而是,我们可以拥有这个程序,因为没有内存泄漏:

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

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

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

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

考虑宇航员并释放您的内存!

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

好吧,这是一个奇怪的问题,因为立即答案很简单:当您将内存丢失到内存泄漏时,您最终可以/最终将耗尽内存。代表特定程序的问题有多大取决于每个泄漏的大小,这些泄漏的频率以及多长时间。这里的所有都是它的。

一个程序,该程序分配相对较低的内存和/或不连续运行的程序可能根本不会遇到任何问题。但是,连续运行的程序最终也会用尽内存,即使泄漏非常缓慢。

现在,如果一个人决定仔细观察它,则每个内存都有两个方面:它占据了过程的地址空间中的地址区域,并且占据了实际物理存储的一部分。p>在没有虚拟内存的平台上,双方都对您不利。内存块泄漏后,您将丢失地址空间,然后将失去存储空间。

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

可以说的是,如果我们采用一个想象中的虚拟内存平台,其地址空间比我们的流程(例如2048位平台和典型的文本编辑器)的任何内容都要大的任何内容,那么内存泄漏将没有对我们计划的结果。但是在现实生活中,记忆泄漏通常构成一个严重的问题。

如今编译器在生成二进制之前对代码进行了一些优化。因此,单一的新事物而不会删除它不会造成太大伤害。

,但总的来说,通过执行任何" newing"您应该"删除"您保留在程序中的内存的部分。

,还要注意,简单的删除不能保证不会用完存储器。O.S.有不同的方面以及控制此功能的编译器侧。

此链接可能会帮助您一点而且这个也是