我刚刚在C中编写了一个代码进行字符串操作的代码,但是当我运行valgrind时,它显示了一些可能的内存泄漏 . 调试代码到粒度级我写了一个简单的C程序,看起来像:
#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
std::string myname("Is there any leaks");
exit(0);
}
并运行valgrind我得到:
==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);
}
10 回答
如果您使用
exit()
insist :此外,当您从
main
返回时,返回的值将成为应用程序的退出代码 . 因此,如果要传递退出代码,请在main()
中使用return exitCode;
而不是exit
.关于那部分:
是的,因为它是一种编程习惯 .
操作系统将清除您未能释放的任何内存,因此只要您没有设法占用所有系统内存和页面文件,就不应该损坏操作系统 .
但是,编写草率/漏洞代码可能会变成习惯,因此依靠操作系统来清理混乱是一个坏主意 .
在
main
末尾使用return 0;
而不是exit(0);
.exit
的使用规避了析构函数的执行 .它对现代操作系统没有害处,因为它们会在流程结束时自动关闭流程所拥有的所有资源 .
然而,它仍然是不好的做法,并且可能导致微妙且难以发现错误,经过几年的维护,代码慢慢变化,直到白天,这确实变得有害 . 我曾参与一些代码已有十年历史的项目,并且我已经学到了一些教训,其中一些相当苛刻 . 因此,即使目前没有出现问题,我也会避免编写这样的代码 .
在大多数情况下,由于已经给出了许多好的理由,因此值得自行清理:更好的可维护性,更好的检查工具实用性等等 .
如果还有其他功能原因要清理,可能您的数据会保存到持久存储中,那么您别无选择 - 您必须清理(尽管您可能想重新考虑您的设计) .
但是,在某些情况下,退出并“泄漏”可能会更好 .
在程序结束时,您的流程将退出 . 当它这样做时,操作系统将恢复程序分配的任何内存,在某些情况下,它可以更快地执行此操作 .
考虑一个大的链表,其中每个节点都是动态分配的,并带有一个实质上动态分配的结构 . 要清理它,您必须访问每个节点并释放每个有效负载(这反过来可能导致其他复杂结构被移动) .
您最终可能会执行数百万次内存操作来运行此类结构 .
用户想退出你的程序,他们坐在那里10秒,等待一堆垃圾处理发生 . 他们不可能对结果感兴趣 - 毕竟他们正在退出计划 .
如果你让这个“泄漏”,操作系统可以更快地回收分配给你的进程的整个内存块 . 它不关心结构和任何对象清理 .
http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx
最终,您必须了解您的工具告诉您的内容,确保您正确使用它们 .
为避免内存泄漏,请从
main
返回状态,而不是调用exit
. 如果你返回零,你可以省略return
语句,如果你愿意;在这种情况下,程序将退出状态为零 .在现代操作系统上,它不会造成任何伤害 - 当程序终止时,所有资源都会自动回收 . 但是,它确实使用像Valgrind这样的工具更难找到真正的问题,所以如果可以的话,最好避免甚至无害的内存泄漏 .
在您的进程实际退出时,就像main()退出时一样,操作系统将回收分配给您的应用程序的所有资源 . 你如何退出并不是那么重要 - 至少在动态记忆方面如此 .
如果你有一些分布式数据库连接打开或者什么,你应该使用atexit()处理程序来关闭它,并且直接退出强制终止可能会使它们无法运行而这将是坏事 - 但就你的操作系统资源而言,可能还好 .
您还应该始终确保释放(手动)文件锁和类似的东西,因为它们可能不会因进程退出而消失 .
如果您想在不超过析构函数的情况下中断执行并传递返回代码,则抛出异常,并从
main()
中的异常中提取返回值 .如果程序正在退出,则不必担心使用
malloc
或new
分配的内存 . 操作系统会处理它 - 你的进程中的任何东西都使用共享内存或命名管道,它仍然是一个问题 .添加不同的意见 .
这样的代码并不是有害的 . 操作系统将在进程终止时关注所有内容 . 其他一切导致操作系统不稳定 . 只需确保您的持久数据(文件,...)一致 .
为了更进一步和挑衅地说明,在程序退出时明确释放内存可能是有害的 .
程序退出需要更长时间(在计算机关闭之前,您是否曾因等待程序退出而烦恼?)
正确的破坏顺序并不总是微不足道的,特别是对于第三方组件(我记得有些程序可能在退出时崩溃)
离开
main
(*)后The OS may not let you free memory并取消你的程序
你冒这个风险只是为了让Valgrind给你一个特定的输出吗?(**)
(*)
(**)当然,任何内存分析器的输出在没有“噪声”的情况下更有用 . 那么在调试模式下退出时只显式释放内存呢?