内存泄漏C++

Memory leak C++

本文关键字:C++ 泄漏 内存      更新时间:2023-10-16

我刚刚用C++写了一段代码,它可以进行一些字符串操作,但当我运行valgrind时,它显示了一些可能的内存泄漏。将代码调试到细粒度级别我写了一个简单的C++程序,看起来像:

#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
        std::string myname("Is there any leaks");
        exit(0);
}

我得到了:

==20943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 26 from 1)
==20943== malloc/free: in use at exit: 360,645 bytes in 12,854 blocks.
==20943== malloc/free: 65,451 allocs, 52,597 frees, 2,186,968 bytes allocated.
==20943== For counts of detected errors, rerun with: -v
==20943== searching for pointers to 12,854 not-freed blocks.
==20943== checked 424,628 bytes.
==20943== 
==20943== LEAK SUMMARY:
==20943==    definitely lost: 0 bytes in 0 blocks.
==20943==      possibly lost: 917 bytes in 6 blocks.
==20943==    still reachable: 359,728 bytes in 12,848 blocks.
==20943==         suppressed: 0 bytes in 0 blocks.
==20943== Reachable blocks (those to which a pointer was found) are not shown.
==20943== To see them, rerun with: --show-reachable=yes

然后我突然意识到我们已经强制退出(这也是我在原始C++代码中执行的)。现在的问题是,我想退出程序,因为我以前的旧代码正在等待新代码的退出状态。例如二进制a.out等待b.out的退出状态。有什么方法可以避免内存泄漏吗?或者我真的应该担心内存泄漏吗,因为程序已经在退出了。

这也给我提出了另一个问题,这样的代码有害吗?

#include<stdio.h>
#include<cstdlib>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}

main末尾使用return 0;而不是exit(0);exit的使用避免了析构函数的执行。

如果您坚持使用exit():

#include<iostream>
int main(){
    {
        std::string myname("Are there any leaks?");
    }
    exit(0);
}

此外,当您从main返回时,返回的值将成为应用程序的退出代码。因此,如果要传递退出代码,请在main()中使用return exitCode;,而不是exit

关于该部分:

这也给我提出了另一个问题,这样的代码有害吗?

是的,因为这是一个BAD编程习惯。

操作系统会清理你未能释放的任何内存,所以只要你没有吃掉所有系统内存和页面文件,就不应该损坏操作系统。

然而,编写草率/泄漏的代码可能会成为一种习惯,所以依赖操作系统来清理你的烂摊子是个坏主意。

这也给我提出了另一个问题,这样的代码有害吗?

#include<stdio.h>
int main()
{
        char *p=(char *)malloc(sizeof(char)*1000);
        exit(0);
}

这对现代操作系统没有害处,因为当进程结束时,它们会自动关闭进程拥有的所有资源。

然而,这仍然是一种糟糕的做法,当经过几年的维护,代码慢慢更改,直到某一天,这确实变得有害时,可能会导致微妙且难以找到的错误。我在一些项目中工作过,其中一些代码已经有十年的历史了,我从中吸取了一些教训,其中一些相当苛刻。因此,我会避免编写这样的代码,即使它目前没有造成问题。

在大多数情况下,它值得自己清理,原因有很多:更好的可维护性,检查工具的实用性更好等等

如果有其他功能原因需要清理,也许你的数据被保存到了一个持久存储中,那么你别无选择——你必须清理(尽管你可能想重新考虑你的设计)。

然而,在某些情况下,最好只是退出并"泄漏"。

在程序结束时,您的进程将退出。当它这样做时,操作系统将恢复程序分配的任何内存,在某些情况下,它可以更快地恢复。

考虑一个大的链表,其中每个节点都是动态分配的,并承载一个实质性的动态分配结构。要清理此问题,您必须访问每个节点并释放每个有效负载(这反过来可能会导致其他复杂结构被遍历)。

您最终可能会执行数百万次内存操作来运行这样的结构。

用户想退出你的程序,他们在那里坐了10秒钟,等待一堆垃圾处理发生。他们不可能对结果感兴趣——毕竟他们要退出这个项目了。

如果让这种"泄漏",操作系统可以更快地回收分配给进程的整个内存块。它不关心结构和任何对象清理。

http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx

最终,你必须了解你的工具在告诉你什么,以确保你正确使用了它们。

要避免内存泄漏,请从main返回状态,而不是调用exit。如果返回零,如果愿意,可以省略return语句;在这种情况下,程序将以零状态退出。

这也给我提出了另一个问题,这样的代码有害吗?

在现代操作系统上,它不会造成任何伤害——当程序终止时,所有资源都会自动回收。然而,这确实使使用Valgrind等工具更难发现真正的问题,因此,如果可以的话,最好避免无害的内存泄漏。

#include<iostream>
using namespace std;
int main()
{
    {
        std::string myname("Is there any leaks");
    }
    exit(0);
}

在进程实际退出时,就像main()退出时一样,操作系统将以任何方式回收分配给应用程序的所有资源。如何退出并不那么重要——至少在动态内存方面是如此。

如果你打开了一些分布式数据库连接或其他什么,你应该使用atexit()处理程序来关闭它,而直接退出的强制终止可能会使它们无法运行,这会很糟糕——但就你的操作系统资源而言,你可能还可以。

您还应该始终确保释放(手动)文件锁和类似的东西,因为它们可能不会因为进程退出而消失。

如果您想在不超过析构函数的情况下中断执行并传递返回代码,请抛出异常,并从main()中的异常中提取返回值。

如果程序正在退出,您不必担心分配给mallocnew的内存。操作系统会处理它——当进程死亡时,进程虚拟地址空间中的任何东西都会消失。如果您使用的是共享内存或命名管道,这可能仍然是一个问题。

添加不同的意见。

这样的代码并没有什么害处。当进程终止时,操作系统将处理所有事务。其他一切都会导致操作系统不稳定。只需确保您的持久数据(文件,…)是一致的。

更进一步,挑衅性的状态,在程序退出时显式释放内存可能是有害的。

  1. 程序退出需要更长的时间(你有没有因为等待程序退出直到计算机关闭而感到恼火?)
  2. 正确的销毁顺序并不总是微不足道的,尤其是对于第三方组件(我记得一些程序可能在退出时崩溃)
  3. 操作系统可能不允许您在离开main(*)后释放内存,而是终止您的程序

你冒这个风险只是为了让Valgrind给你一个特定的输出吗?(**)


(*)

#include<iostream>
using namespace std;
std::string myname("Is there any leaks");
int main() {
        exit(0);
}

(**)当然,任何内存分析器的输出在没有"噪音"的情况下都更有用。在调试模式下,只在退出时显式释放内存怎么样?