代码之家  ›  专栏  ›  技术社区  ›  Thomas Flinkow

进程终止时是否回收内存?

  •  10
  • Thomas Flinkow  · 技术社区  · 8 年前

    在我的一个应用程序中,我基本上是在 C++ 并将其排队以便在 C# . 这种解除分配在后台运行,并且是不确定的,因此 在极少数情况下 理论上,在释放所有非托管内存之前退出应用程序是可能的。

    如果是这样的话,行为(大致和非常精简)与我的程序相同

    int main()
    {
       Foo* = new Foo();
       return 0;
    }
    

    我现在的问题是

    • 当程序退出时,是否会自动回收程序分配但未取消分配的所有内存,还是内存泄漏一直持续到我重新启动?
    • 如果自动回收,是什么机制造成的?

    编辑: 这只是关于Windows的,正如一些人提到的,这取决于操作系统。

    编辑2: 我说的不是简单地忽略应用程序中的所有内存泄漏,而是我是否需要确保在应用程序退出之前正确释放所有内存。

    编辑3: 这不是关于打开的文件句柄、析构函数和副作用或任何东西,这是关于非确定性释放的内存,以及在终止之前内存未释放的极少数情况。

    5 回复  |  直到 8 年前
        1
  •  4
  •   Sergey Kalinichenko    8 年前

    当程序退出时,是否会自动回收程序分配但未取消分配的所有内存,还是内存泄漏一直持续到我重新启动?

    当进程终止时,操作系统会自动回收内存。

    如果自动回收,是什么机制造成的?

    C++的内存管理器,落后者 new , delete , malloc 等从操作系统中获取相对较大的内存块,并负责管理粒度小得多的内存块。操作系统跟踪已分配给进程的所有内存,并在进程终止时回收它。

        2
  •  3
  •   Basile Starynkevitch    8 年前

    如果您只关心内存,则可能不需要调用 delete 因为操作系统会破坏你的整个 virtual address space process 结束考虑阅读 Operating Systems: Three Easy Pieces (可免费下载)以了解有关操作系统的更多信息。

    但是你想避免 memory leak s、 所以你最好好好打扫。在某些操作系统上,您可以使用以下工具: valgrind 帮助检测此类泄漏(因此您不希望他们发出虚假警告)。

    另请阅读 RAII . 在现实生活中,的构造函数(或其他方法) Foo (或it使用的间接数据)可能会消耗其他资源(数据库连接、打开的文件、屏幕上的窗口、守护进程、到外部服务或web服务器的远程连接、机器人手臂等)你希望他们被妥善处理。

    考虑使用 smart pointers .

    数据结构的活性是 整个程序 所有物我建议阅读 GC handbook ,至少要理解 garbage collection (这可以看作是管理资源的一种方式,而不仅仅是管理原始内存)。

    (实际上, 这取决于很多 :如果你正在与数百名其他程序员一起编写一百万行代码程序,那么你需要比单独编写一个很小的源文件程序更加小心;如果你编写一个神经手术机器人,它与桌面应用程序不同,等等。。。。so YMMV)

        3
  •  3
  •   Detonar    8 年前

    除非你是在开发低水平的软件,否则你是在操作系统下工作的。该操作系统管理真实内存,为应用程序提供映射到真实内存的虚拟内存。

    应用程序关闭(进程终止)后,操作系统会删除虚拟内存映射,释放该进程的所有内存资源。

        4
  •  2
  •   OriBS    8 年前

    答案是,Windows应该在你之后清理内存,如果它不这样做,就应该被视为操作系统中的一个bug。对于Linux和任何其他允许您过早终止进程的系统来说也是如此。

    原因是,如果我理解正确的话,您描述的情况与以下情况更为相似:

    int main()
    {
       Foo* foo = new Foo();
       // The process is being brutally kill here. (kill -9 or Windows equivalent)
       delete foo;
       return 0;
    }
    

    因此,即使你做了你应该做的一切,并在自己正确清理后,由于操作系统选项过早地杀死你的进程,它会导致内存泄漏。

    最后,一个重要的澄清,这并不意味着你可以忽略所有的话题,你应该尽最大努力在自己之后清理,不要指望其他系统在你之后清理。

        5
  •  2
  •   cmaster - reinstate monica    8 年前

    内存分配有两个不同的级别:

    1. 从操作系统到进程的内存分配。这需要 syscall (或者 brk() mmap() ),并完全由实现定义。 你自己从来没见过。

    2. 从进程到单个数据对象的内存分配。这是什么 operator new()

    new 返回指向数据对象的指针,因此主要与第二级有关。然而 它本身没有可以分配给对象的内存,除非它先向操作系统请求一些内存。因此,它需要首先执行一级分配。

    实施 它本身完全在你的过程中。因此,当您的进程以非自然方式死亡(由于信号而终止)时 实现没有机会清理任何东西。但这不是必要的,因为操作系统本身会跟踪在第一级分配的内存。它只是不信任一些随机进程来跟踪其分配的内存本身。因此,不会发生永久性内存泄漏。

    然而,未能 delete 使用创建的对象 会产生以下后果:

    • 实现将需要进行越来越多的一级内存分配,直到您的操作系统没有剩余内存可供进程使用。

    • 删去 意味着没有调用相应的析构函数。因此,您的进程可能会错过一些外部清理。例如,未能销毁对象可能意味着某些临时文件没有从文件系统中删除,因此进程会泄漏磁盘空间而不是内存。你也不想这样,是吗?