我一直在努力确定我看到的是否是我的 Debian Wheezy Mono-Sgen 2.10.8.1-8 嵌入式应用程序中的内存泄漏。该系统有 512MB 的 RAM。交换被禁用。我一直在研究试图了解 Linux 如何管理进程内存,以确定我所看到的是否实际上是 Mono-Sgen 中某处的内存泄漏。我很确定这不是我的应用程序,因为经过数周的恒定运行时间后,我已经对其进行了多次分析,并且 GC 内存总是回落到应用程序的基线。从我的应用程序的角度来看,没有任何对象泄漏。这并不意味着 Mono-Sgen 内部没有泄漏,但我还没有确定这一点,也可能不是。
我试图限制我的 Mono-Sgen 堆,因为大型堆的 mono 的默认值是 512MB,因为这是我的系统所拥有的全部,我认为我需要限制它以防止 Linux 出现 OOM。我对 Mono-Sgen 的配置如下:
export MONO_GC_PARAMS=major=marksweep-fixed,major-heap-size=32m,nursery-size=4m,疏散阈值=75
据我了解,我正在使用 32MB 固定大小的标记和清除固定主堆,默认托儿所大小为 4MB,如果任何主堆分配桶低于 75,Mono-Sgen 将在主堆上执行复制收集% 用于防止碎片。我提高了 66% 的默认值。
自从停电导致重置后,我的设备目前已经运行了 6 天多一点。当我的应用程序第一次启动时,我等待大约 10 分钟以确保它已完全初始化,然后我拍摄 /proc/PID/status 文件的快照以获取其内存使用情况的基线。今天,我又开了一家快照商店,看看我在哪里,并且一如既往,我的虚拟、驻留和 Mono-Sgen 流程实例的数据再次增长。它尚未突破初始化期间出现的高水位线,但我上次进行此测试时确实如此。我没能做的和我想要完成的是让它运行到耗尽系统所有物理内存的地步。我需要知道这是否实际上是内存泄漏,或者 Linux 是否会在某个时候回收我的进程分配的一些页面。
我注意到的一件事是,即使知道我没有交换,我的 Mono-Sgen 进程的常驻大小总是比数据数少 30MB。据我了解,数据计数是堆分配量,常驻大小是物理内存中的实际大小,虚拟是已分配的,不一定使用。
我的假设是,Linux 只是 Linux,除非必须,否则不会浪费时间或内存。我假设由于系统负载非常轻,Linux 的内存压力为 0,可以做任何事情来回收内存,以免 Mono-Sgen 继续分配和增长堆,我希望当有一些实际的内存压力时,Linux 会继续介入并回收未真正使用的页面。
我已经读过,当在先前分配的内存上调用 free 时,Linux 不会缩小进程的分配内存大小。我不明白为什么,除非 Linux 是 Linux,否则它只会在必要时这样做。但我担心的是我需要等多久才能发生这种情况。
这是内存泄漏,还是当内存压力开始出现时,Linux 会回收该进程的驻留和数据大小之间的页面差异?我已经搜索并阅读了有关该主题的所有内容,但我没有找到我正在寻找的答案,并且真的不想等待一个月来确定我的申请是否会因为 OOM 杀手而被退回。无论如何我都会:)但我想事先知道。
我已经研究了 Mono-Sgen 2.10.8.1-8 的潜在内存泄漏,但是对于我正在做的事情(使用大量 process.start() 调用本机 Linux 应用程序)大多数类型的错误会伤害我不在此版本中。我尝试更新到 Jessie 的 Mono-Sgen 版本(我认为是 3.2.8),但它在我的系统上崩溃了,所以出于更多未知的恐惧,我恢复到了稳定的 Mono-Sgen 2.10.8.1-8 版本。
附件是典型内存信息的大量快照,我的大部分注意力都集中在 /proc/PID/status 返回的内容上。
任何信息都将一如既往地受到赞赏,我希望我只是不明白 Linux 如何在轻负载系统上回收内存。