5

一般规则,只有在空闲存储中分配的对象才会导致内存泄漏。但是在堆栈中创建的对象没有。

这是我的疑问,

int main()
    {
      myclass x;

      ...

      throw;

      ...
    }

如果 throw 没有被处理,它会调用 terminate(),然后调用 abort() 并使应用程序崩溃。此时,堆栈中的对象没有被销毁(没有调用析构函数)。

我的理解是“当应用程序终止时(通过中止或正常退出),它会释放为应用程序分配的所有内存”。因此这不能被视为内存泄漏。

我对么?

4

7 回答 7

5

在托管环境(例如典型的 Unix / Windows / Mac OS X,甚至 DOS 机器)中,当应用程序终止时,它占用的所有内存都会被操作系统自动回收。因此,担心这种内存泄漏是没有意义的。

在某些情况下,在应用程序终止之前,您可能希望释放您分配的所有动态内存,以便通过泄漏检测器(如valgrind )检测潜在的内存泄漏。但是,即使在这种情况下,您描述的示例也不会被视为内存泄漏。

通常,未能调用析构函数与导致内存泄漏不同。内存泄漏源于堆上分配的内存(使用 new 或 malloc 或容器分配器)。当堆栈展开时,分配在堆栈上的内存会自动回收。然而,如果一个对象拥有一些其他资源(比如文件或窗口句柄),未能调用其析构函数将调用资源泄漏,这也可能是一个问题。同样,现代操作系统将在应用程序终止时回收其资源。

于 2010-08-25T21:06:46.620 回答
4

编辑:正如 GMan 所说,“投掷;” 重新抛出之前抛出的异常,或者如果没有,则立即终止。由于在这种情况下没有,因此结果是立即终止。

终止进程始终会清除任何现代操作系统中的任何剩余用户空间内存,因此通常不被视为“内存泄漏”,它被定义为未在运行进程中释放的未引用内存。但是,这种事情是否被认为是“内存泄漏”实际上取决于操作系统。

于 2010-08-25T20:59:30.047 回答
2

答案是,这取决于操作系统。我想不出一个不这样做的现代操作系统。但是旧系统(我认为在 windows 中赢得 3.1 和一些旧的嵌入式 Linux 平台)如果程序在没有释放其内存请求的情况下关闭,操作系统会保留它们直到你重新启动。

于 2010-08-25T20:58:56.777 回答
1

内存泄漏被认为是一个问题,因为长时间运行的应用程序会慢慢耗尽系统内存,并且在最坏的情况下,由于内存不足,可能会使整个机器无法使用。在您的情况下,应用程序终止并且分配给应用程序的所有内存都将返还给系统,所以几乎没有问题。

于 2010-08-25T20:59:56.387 回答
1

真正的问题是,“myclass 本身是否分配了任何必须释放/删除的内存?”

如果没有——如果它使用的唯一内存是它的内部成员——那么它就完全存在于堆栈中。一旦它离开该函数(无论如何),堆栈上的内存就会被回收和重用。 myclass离开了。这就是堆栈的工作方式。

如果 myclass 确实分配了需要在它的 dtor 中释放的内存,那么你仍然很幸运,因为在 throw 期间堆栈未展开时将调用 dtor。在异常被声明为未处理并调用终止之前,dtor 已经被调用。

唯一会遇到问题的地方是 myclass 是否有 dtor,并且 dtor 作为它自己的异常抛出。在从第一次抛出的堆栈展开期间发生的第二次抛出将使其调用立即终止,而无需调用任何更多的 dtor。

于 2010-08-25T21:10:01.363 回答
1

来自 OP,

如果 throw 没有被处理,它会调用 terminate(),然后调用 abort() 并使应用程序崩溃。此时,堆栈中的对象没有被销毁(没有调用析构函数)。

这是实现定义的行为。

$15.3/9-“如果在程序中找不到匹配的处理程序,则调用函数 terminate();在调用 terminate() 之前是否展开堆栈是实现定义的 (15.5.1)。”

因此,我猜这是否构成内存泄漏也是实现定义的行为。

于 2010-08-26T02:25:25.543 回答
0

我的理解是“当应用程序终止时(通过中止或正常退出),它会释放为应用程序分配的所有内存”。因此这不能被视为内存泄漏。

我对么?

内存泄漏是一种编程错误,与未捕获的异常相比,它在编程错误的规模上排名稍低。

IOW,如果程序没有正确终止,也就是崩溃,那么现在谈论内存泄漏还为时过早。

另一方面,我在过去十年中使用过的大多数内存分析器在这种情况下都不会触发任何内存泄漏警报——因为当程序愚蠢地崩溃时它们不会触发任何警报。首先必须使程序不崩溃,然后才能调试内存泄漏。

于 2010-08-25T21:30:13.977 回答