还有一个内存泄漏问题(当程序终止时,内存仍然没有)-SLES上的C程序



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

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

最上面的程序只显示程序在运行时最多使用4%左右的内存。

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

问题:

  1. 是否存在malloc()/free()不匹配,从而永久丢失内存,即即使在进程完成之后?

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

  3. 查看顶部并自由查看内存统计数据是否有效,即它们是否准确描述了内存情况?它们似乎确实与程序的缓慢相对应。

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

是否存在malloc()/free()不匹配,从而永久丢失内存,即即使在进程完成之后

不,malloc和free,甚至mmap在这方面都是无害的,当进程终止时,OS(在本例中为SUSE Linux)会收回所有内存(除非它与其他仍在运行的进程共享)。

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

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

有一些东西会导致永久性内存泄漏,比如大页面,但如果你使用它们,你肯定会知道的。除此之外,没有。


但是,如果您将内存丢失定义为未立即标记为"free"的内存,则可能会发生以下情况。

  1. 对磁盘或mmap的写入可能会在RAM中缓存一段时间。操作系统必须保留这些页面,直到将它们同步回磁盘
  2. 如果操作系统目前没有其他东西可以使用RAM,则进程读取的文件可能会保留在内存中——合理的假设是,它可能很快就会需要这些文件,并且读取RAM中已经存在的副本会更快。同样,如果操作系统或另一个进程需要一些RAM,它可以立即被丢弃

请注意,作为一个为我所有的RAM付费的人,我宁愿操作系统一直使用所有的RAM,如果它能以最小的方式提供帮助的话。空闲RAM是浪费的RAM。


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

有时,内存泄漏可能会导致临时过度投入——最好对此进行研究。试着绘制程序的内存使用情况——如果它持续上升,那么很可能是泄漏。

请注意,进程中的fork会创建一个副本,共享原始分配的内存,直到两者都关闭或其中一个"exec"为止。但你没有那样做。

查看顶部并自由查看内存统计数据是否有效,即它们是否准确描述了内存情况?它们似乎确实与程序的缓慢相对应


是的,topps是观察内存的非常合理的方法,特别是观察RES字段。暂时忽略VIRT字段。此外:

要查看整个系统对内存的处理情况,请运行:

vmstat 10

当您的程序正在运行时以及之后的一段时间。看看---memory---列发生了什么。

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

cat /proc/meminfo

并将结果张贴在你的问题中。

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

可能,但可能非常慢,在这种情况下可能不切实际。还有很多其他工具可以帮助你,比如电动工具和其他工具,它们不会显著降低你的程序。我过去甚至有过自己的经历。

malloc()/free()在堆上工作。该内存保证在进程终止时释放给操作系统。即使在使用某些共享内存基元(例如System 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可用于需要它的程序。请参阅帮助!Linux吃掉了我的RAM!了解更多信息。

我不能说为什么程序越来越慢,但"空闲内存"指标稳步下降到零是完全正常的,而不是原因。

操作系统只释放绝对需要的内存。如果内存后来被正常使用,那么释放内存是徒劳的——直接将内存从一种使用转换到另一种使用比释放内存以便稍后解冻更有效。

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

如果您键入此命令sysctl vm.min_free_kbytes,系统将告诉您需要空闲的KB数。它可能不到100MB。因此,拥有比免费数量更多的东西是完全可以的。

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

例如,考虑您写入磁盘的数据。操作系统可以释放保存该数据的内存。但这是双重损失。如果您写入磁盘的数据后来被读取,它将不得不从磁盘中读取,而不仅仅是从内存中获取。如果这些内存后来被用于其他目的,它只需要撤销所有使其免费所做的工作。恶心。因此,如果系统不绝对需要空闲内存,它就不会使其空闲。

我猜问题不在程序中,而是在操作系统中。操作系统将最近使用的文件缓存在内存中,假设您将再次访问它们。它不确定需要什么文件,所以它最终可能会决定保留错误的文件,而牺牲你希望它保留的文件。

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

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

回答

  1. 是的,在C或C++中没有要求将未释放的内存释放回操作系统
  2. 您是否有内存映射文件、已删除文件的打开文件句柄等。在释放所有对的引用之前,Linux不会删除文件。此外,linux会将文件缓存在内存中,以防需要再次读取-文件缓存内存的使用可以忽略,因为操作系统会处理它
  3. 也许valgrind会强调记忆缺失的情况

最新更新