【问题标题】:How to avoid memory leak when user press ctrl+c under linux?linux下用户按ctrl+c时如何避免内存泄漏?
【发布时间】:2017-08-01 22:27:28
【问题描述】:

在我用 C 和 C++ 编写的程序中,我会新建一个对象来完成任务,然后删除该对象。

在new对象之后delete对象之前,如果用户按ctrl+c来中断进程,会导致delete不被调用,a发生内存泄漏。

我应该怎么做才能避免这种情况?

另外,如果内存被操作系统回收了,那么打开的文件呢?它们是由操作系统关闭还是我应该手动关闭它们?

【问题讨论】:

  • 有人可以请 s/Linux/Unix/ 概括一下吗?

标签: c memory-leaks


【解决方案1】:

在基于虚拟内存的系统中,当进程终止时,所有内存都会返回给操作系统,无论它是否在应用程序代码中显式释放。但是,其他资源可能并非如此,您可能希望干净地释放这些资源。在这种情况下,您需要为SIGINT 信号(在 Ctrl+C 上接收)提供自定义信号处理程序,参见例如http://linux.die.net/man/2/sigaction.

【讨论】:

  • 这是否意味着我不应该关心分配的内存?但我发现我的析构函数没有被调用。打开的文件也被操作系统关闭了?
  • @PDF1001- 即使操作系统为您完成了一些工作,尽可能多地自己清理总是一个好主意。操作系统不会调用你的析构函数,它会直接释放你程序分配的所有内存。如果我没记错的话,在文件句柄方面你是靠自己的。如有疑问,请谨慎行事,不要认为操作系统会做任何事情。
【解决方案2】:

当进程因 Ctrl-C 或任何其他方式退出时,操作系统将回收进程分配的内存。

【讨论】:

    【解决方案3】:

    CtrlC 将向进程发送SIGINT,默认情况下,进程会按顺序关闭,包括拆除内存管理器并释放所有分配的堆和栈。如果您需要执行其他任务,则需要安装 SIGINT 处理程序并自己执行这些任务。

    【讨论】:

      【解决方案4】:

      当在 Linux 控制台中按下 CTRL+C 时,SIGINT 信号被发送到应用程序,如果该信号没有处理程序,将终止程序,将所有内存返回给操作系统。这当然会使任何内存释放变得毫无意义,因为一旦程序存在,所有内存都会被释放。但是,如果您想处理 CTRL+C SIGINT 信号(可能将一些最后的数据写入文件或进行其他一些清理),您可以使用函数signal() 来安装一个函数,以便在收到信号时调用收到。如果您想了解更多信息,请查看此功能的手册页。

      【讨论】:

        【解决方案5】:

        如果您使用 shmget(2) 分配了任何 SYSV 共享内存段,那么您必须自己使用 shmctl(2) 进行清理。

        如果您使用 shm_open(3) 分配了任何 POSIX 共享内存段,那么您必须自己使用 shm_unlink(3) 进行清理。

        SYSV 和 POSIX 共享内存段在进程终止后仍然存在。您可以使用ipcs(1) 工具查看持续存在的内容。

        当然,如果您没有使用任何 SYSV 或 POSIX 共享内存段,那么这一切都只是噪音。 :)

        【讨论】:

          【解决方案6】:

          如果进程退出,一般不会发生内存泄漏。

          您分配的大部分内存将在 Ctrl+C 时释放。如果您发现内存使用量没有恢复到之前的水平,那几乎可以肯定是由缓冲的文件系统块引起的。

          但是,您绝对应该清理这些东西,尤其是如果您使用了任何其他类型的资源:

          • 在临时目录中创建的文件不会被删除。这包括 /dev/shm,留下这样的文件可能被视为“内存泄漏”。
          • 当您的进程退出时,System V 或 posix 共享内存段不会被丢弃。如果这让您感到困扰,请专门清理它们。或者,在后续运行时清理它们。

          通常,如果后续运行不泄漏更多内存,则泄漏(持久或半持久对象,例如文件)并不重要。因此,在未来的运行中进行清理就足够了。

          想象一个从“cron”开始每 5 分钟运行一次的进程,如果它在每次运行时都崩溃并留下一些混乱,但只要每次运行都能清除上一次崩溃造成的混乱,它仍然可以。

          【讨论】:

            【解决方案7】:

            您订阅了一个相当普遍的误解,即未释放但在程序存在时仍可访问的堆块是泄漏。这不是真的。泄漏块是那些没有指针仍然引用的块,因此它们不能被释放。

            多年来,我一直在使用(并破坏)许多非常好的内核,但我从未设法充分破坏虚拟内存管理器,使其在退出后不再回收进程的整个地址空间。除非你正在使用一个明确标记为“新的和实验性的”内核,否则你会比找到一个没有使用有效虚拟内存管理器的系统更幸运。

            不要为了在 Valgrind 中获得满分而在代码中添加粗俗。如果除了释放仍然有有效引用的内存之外,您没有真正的清理任务要执行其他,那么您无需费心。如果有人向您的程序抛出kill -9,您将无法处理它并且会看到旧行为重复。

            如果您有要清理的文件描述符、要放弃的共享锁、要刷新的流或任何其他必须发生的事情,以便其他进程在您离开时不会错过您,请务必处理好这些。只是不要添加对解决非问题无用的代码,这样做似乎很愚蠢。

            注意

            这本来是一个评论,但是太长了,所以不赞成一次写一篇评论。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-05-13
              • 1970-01-01
              • 1970-01-01
              • 2018-04-08
              相关资源
              最近更新 更多