又一个内存泄漏问题(程序终止时内存仍然消失) - SLES上的C程序

时间:2012-09-08 03:04:13

标签: c memory-leaks malloc suse

我在Suse Linux Enterprise上运行我的C程序,它压缩了数千个大文件(大小在10MB到100MB之间),程序运行时程序越来越慢(它运行多线程32 Intel Sandy Bridge板上的线程)。当程序完成并再次运行时,它仍然非常慢。

当我观看程序运行时,我发现在程序运行时内存正在耗尽,您认为这只是一个典型的内存泄漏问题。但是,由于正常的malloc()/ free()不匹配,我希望在程序终止时返回所有内存。但是,程序完成后,大部分内存都无法回收。 free或top命令显示Mem:63996M total,63724M used,当程序减速到停止时272M free,但是,在终止后,空闲内存只会增长回到3660M左右。重新运行程序时,可用内存很快就会用完。

顶级程序仅显示程序在运行时最多使用4%左右的内存。

我认为它可能是内存碎片问题,但是,我构建了一个小型测试程序,模拟程序中的所有内存分配活动(许多随机方面都是内置的 - 大小/数量),它总是返回所有完成后的记忆。所以,我不这么认为。

问题:

  1. 是否存在malloc()/ free()不匹配会永久丢失内存,即使在该过程完成后也是如此?

  2. C程序(不是C ++)中的其他什么东西会导致永久性内存丢失,即程序完成后,甚至终端窗口关闭?只有重新启动才能恢复内存。我已经阅读了其他关于文件未被关闭导致问题的帖子,但是,我不认为我有这个问题。

  3. 查看内存统计数据是否有效,是否有效,即它们是否准确描述了内存情况?它们似乎与程序的缓慢程度相符。

  4. 如果程序只显示4%的内存使用量,valgrind会发现这个问题吗?

5 个答案:

答案 0 :(得分:4)

是否存在malloc()/ free()不匹配会永久丢失内存,即使在该过程完成后也是如此?

不,free,甚至在这方面都是无害的,并且当进程终止操作系统(在这种情况下为SUSE Linux)时,他们会回复所有内存(除非它与其他正在运行的进程共享。)

C程序(不是C ++)中的其他什么东西会导致永久性内存丢失,即程序完成后,甚至终端窗口关闭?只有重新启动才能恢复内存。我已经阅读了其他关于文件未被关闭导致问题的帖子,但是,我认为我没有这个问题。

与malloc / free和mmap一样,该进程打开的文件将由操作系统自动关闭。

有一些事情导致永久性内存泄漏,例如大页面,但如果您使用它们,您肯定会知道它。除此之外,没有。


但是,如果您将内存丢失定义为内存未立即标记为“ free ”,则可能会发生一些事情。

  1. 写入磁盘或mmap可能会在RAM中缓存一段时间。操作系统必须保留页面,直到它们将它们同步回磁盘。
  2. 如果操作系统现在没有其他任何东西可以使用该RAM,那么进程的文件读取可能会保留在内存中 - 在合理的假设下,它可能很快就需要它们,并且可以更快地读取已经在RAM中的副本。同样,如果操作系统或其他进程需要某些RAM,则可以立即将其丢弃。
  3. 请注意,作为支付我所有内存的人,我宁愿操作系统一直使用所有内容,如果它以最小的方式帮助它。免费RAM浪费了RAM。


    拥有少量空闲RAM的主要问题是当过度使用时,也就是说现在有更多进程(和操作系统)要求或使用RAM而不是系统上可用的RAM 。听起来你在你的进程中使用大约4Gb的RAM,这可能是一个问题 - (并且记住操作系统也需要一个很好的块。但是听起来你有足够的RAM!尝试运行一半的进程并看到如果它变得更好。

    有时内存泄漏会导致暂时过度使用 - 最好还是考虑一下。尝试在一段时间内绘制程序的内存使用情况 - 如果它连续上升,那么很可能是泄漏。

    请注意,fork进程创建一个副本,共享原始分配的内存 - 直到两者都关闭或其中一个'exec'。但你不是那样做的。

    查看内存统计数据是否有效,是否有效,即它们是否准确描述了内存情况?它们似乎与程序的缓慢程度相符。


    是的,topps是查看内存的完美合理方式,尤其是观察RES字段。暂时忽略VIRT字段。另外:

    要查看整个系统对内存的作用,请运行:

    vmstat 10
    

    当你的程序运行一段时间之后。看看---memory---列会发生什么。

    此外,在您的流程完成后,运行

    cat /proc/meminfo
    

    并将结果发布在您的问题中。

    如果程序只显示4%的内存使用量,valgrind会发现这个问题吗?

    可能,但它可能非常慢,在这种情况下可能是不切实际的。还有很多其他工具可以提供帮助,例如electricfence and others,这些工具不会显着降低您的程序。我过去甚至自己动手了。

答案 1 :(得分:2)

malloc()/ free()在堆上工作。保证在进程终止时将此内存释放到操作系统。即使在分配过程使用某些共享存储器基元(例如,系统V IPC)终止之后,也可能泄漏存储器。但是,我不认为这与任何直接相关。

稍微退一步,这是来自一个负载很轻的Linux服务器的输出:

$ uptime
 03:30:56 up 72 days,  8:42,  2 users,  load average: 0.06, 0.17, 0.27
$ free -m
             total       used       free     shared    buffers     cached
Mem:         24104      23452        652          0      15821        978
-/+ buffers/cache:       6651      17453
Swap:         3811          5       3806

哦不,只有652 MB免费!对?错。

每当Linux访问块设备(例如,硬盘驱动器)时,它会查找任何未使用的内存,并在那里存储数据的副本。毕竟,为什么不呢?数据已经在RAM中,某些程序显然希望数据和未使用的RAM不能对任何人有任何好处。如果程序出现并请求更多内存,则会丢弃缓存的数据以腾出空间 - 在此之前,还可以挂起它。

free输出的关键不是第一行,而是第二行。是的,正在使用23.4 GB的RAM - 但是17.4 GB可用于需要它的程序。有关详情,请参阅Help! Linux ate my RAM!

我不能说为什么程序变慢了,但是将“空闲记忆”指标稳定地降到零是完全正常而不是原因。

答案 2 :(得分:1)

操作系统只能提供绝对需要的无内存。如果以后正常使用内存,那么释放内存就会浪费精力 - 只需将内存从一个用户直接转换到另一个用户,而不是让内存空闲只是为了让以后不再使用它就更有效了。

系统唯一需要空闲内存的是需要内存的操作,这些内存无法将使用过的内存从一个目的切换到另一个目的。这是一组非常小的异常操作,例如服务网络中断。

如果您键入此命令sysctl vm.min_free_kbytes,系统将告诉您它需要的KB数量。它可能不到100MB。因此,任何超过免费的金额都是完全正常的。

如果您想要更多内存空闲,请将其从计算机中删除。否则,操作系统假定使用它的成本为零,因此使其免费为零。

例如,考虑您写入磁盘的数据。操作系统可以使保存该数据的内存空闲。但这是双重损失。如果稍后读取写入磁盘的数据,则必须从磁盘读取数据而不是从内存中读取数据。如果稍后需要该内存用于某些其他目的,则只需撤消其通过使其免费所做的所有工作。呸。因此,如果系统不是绝对需要空闲内存,它就不会免费。

答案 3 :(得分:0)

我的猜测是问题不在您的程序中,而是在操作系统中。操作系统假设您将再次访问它们,在内存中保留最近使用的文件的缓存。它不确定知道将需要哪些文件,因此最终可能会以牺牲您希望保留的文件为代价来决定保留错误文件。

第二次运行时,可能会保留第一次运行的输出文件,这会阻止它在第二次运行时有效地使用缓存。您可以通过删除第一次运行中的所有文件(这应该从缓存中释放它们)并查看是否使第二次运行更快来测试此理论。

如果这不起作用,请尝试删除第一次运行的所有输入文件。

答案 4 :(得分:-1)

答案

  1. 是的,C或C ++中没有要求释放未释放回操作系统的内存
  2. 您是否有内存映射文件,打开已删除文件的文件句柄等。在所有引用都被取消分配之前,Linux不会删除文件。此外,linux会将文件缓存在内存中,以防需要再次读取 - 文件缓存内存使用量可以忽略,因为操作系统会处理它
  3. 没有
  4. 也许valgrind会突出显示内存不是
  5. 的情况