这些难搞的内存问题你都懂了吗?
内容提要
本文介绍了Linux内核内存管理的相关知识,包括进程内存的申请和分配过程、OOM时的情况以及系统申请的内存存放位置和回收方式。
延伸解读
OOM 触发条件与 overcommit 策略
文章指出 OOM 并非仅由物理内存耗尽引起,还与 overcommit_memory 设置有关。当值为 0 时,若虚拟内存申请远超物理内存,即使物理内存充足也可能触发 OOM;值为 1 时允许任意超额申请,直到物理内存真正耗尽才 OOM;值为 2 则严格限制申请总量。理解这一机制有助于解释为何某些进程在内存看似够用时仍被杀死。
不同映射方式的内存归属差异
文章通过实验对比了四种 mmap 映射:共享文件映射和共享匿名映射的内存会计入 buff/cache,私有文件映射在写入时触发写时复制,同时增加 used 和 buff/cache,而私有匿名映射只增加 used。这说明进程内存并非都占用普通物理内存,部分以 pagecache 形式存在,影响 free 命令的解读和内存回收策略。
drop_caches 的释放边界
手动执行 echo 1 > /proc/sys/vm/drop_caches 可释放 pagecache 中可回收的部分,但文章强调脏页需先 sync 刷盘才能释放。此外,被进程引用的文件映射页、共享匿名映射页以及基于 tmpfs 的共享内存和 IPC 机制占用的 pagecache 均无法通过 drop_caches 释放,因为它们有文件或内核引用。这解释了为何有时释放缓存后内存占用仍居高不下。
自动回收机制与 swap 权衡
内核通过 kswapd 线程周期性扫描 LRU 链表回收内存:文件页若为脏页则回写磁盘后释放,非脏页直接释放;匿名页则需 swap out 到磁盘。文章提到 swap 换入换出会占用大量 IO,若内存需求突增可能导致系统卡死。参数 swappiness 控制回收时使用 swap 的倾向,值越高越倾向于 swap 匿名页,设为 0 则尽量回收 cache。这提示需根据业务特点调整该参数以平衡性能与内存释放。
Q&A
Linux进程启动时,内存是如何申请和分配的?
终端进程调用exec函数将可执行文件载入内存,代码段、数据段、bss段、stack段通过mmap函数映射到内存空间,堆则根据是否申请内存决定是否映射。exec执行后,动态链接库装载器将所需动态库装载进内存,之后进程开始执行。第一次调用malloc时,通过brk系统调用进入内核,若没有堆的vma,则通过mmap匿名映射一块内存给堆并建立vma结构。用户态申请大内存时直接调用mmap分配虚拟内存,直到第一次访问时才真正分配物理内存。
Linux的OOM killer是如何选择要杀死的进程的?
OOM时,内核函数select_bad_process会遍历所有进程,根据进程占用内存、运行时间、优先级、是否为root用户进程、子进程个数和占用内存以及用户控制参数oom_adj等因素计算每个进程的oom_score分数,分数最高的进程将被杀死。可以通过设置/proc/<pid>/oom_adj来干预,范围是-16到15,设置为-17则进程不会被杀死。
overcommit_memory参数的不同取值对OOM有什么影响?
overcommit_memory为0时,采用启发式oom,如果申请的虚拟内存远大于物理内存则产生OOM;为1时,永远允许内存申请,直到物理内存耗尽才产生OOM;为2时,不能超出限定额(swap+RAM*overcommit_ratio),超出则申请内存返回错误。
mmap的不同映射方式(共享文件、私有文件、私有匿名、共享匿名)的内存分别存放在哪里?
共享文件映射(如代码段、动态链接库)将文件映射到内核cache中;私有文件映射(如数据段)先将文件映射到cache,写时复制时从其他内存分配新页;私有匿名映射(如bss、堆、栈)不占用cache,直接使用普通物理内存;共享匿名映射从cache中申请内存,用于父子进程共享。
如何手动回收Linux系统的内存?drop_caches有什么限制?
可以通过echo 1 >> /proc/sys/vm/drop_caches手动回收pagecache,echo 2回收dentries和inodes缓存,echo 3同时回收两者。但如果有脏数据,需要先执行sync刷新到磁盘才能释放。此外,被进程引用的pagecache(如代码段、共享匿名映射、tmpfs文件、共享内存)不能通过drop_caches释放。
Linux内核的kswapd线程如何自动回收内存?
kswapd周期性地检查内存使用情况,当空闲内存低于pages_low时,扫描LRU链表,将活跃链表中的不活跃页移到不活跃链表,然后回收不活跃页直到空闲页达到pages_high。对于文件页,脏页回写磁盘后回收,非脏页直接释放;对于匿名页,则swap out到磁盘并在页表项做标记,下次访问时swap in。
tmpfs文件系统的内存可以回收吗?它有什么特点?
tmpfs是基于内存的文件系统,其文件占用的pagecache不能通过drop_caches回收,因为有文件引用这些页。tmpfs可以使用swap空间,并且可以限定使用内存大小,与ramfs不同。常见的tmpfs挂载点是/dev/shm。