一、linux内存框图
二、meminfo信息说明
cat /proc/meminfo
MemTotal: 2017504 kB //所有可用的内存大小,
物理内存减去预留位和内核使用。系统从加电开始到引导完成,firmware/BIOS要预留一
些内存,内核本身要占用一些内存,最后剩下可供内核支配的内存就是MemTotal。这个值
在系统运行期间一般是固定不变的,重启会改变。
MemFree: 511052 kB //表示系统尚未使用的内存。
MemAvailable: 640336 kB //真正的系统可用内存,
系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可
以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存
Buffers: 114348 kB //用来给块设备做缓存的内存,(文件系统的 metadata、pages)
Cached: 162264 kB //分配给文件缓冲区的内存,例如vi一个文件,就会将未保存的内容写到该缓冲区
SwapCached: 3032 kB //被高速缓冲存储用的交换空间(硬盘的swap)的大小
Active: 555484 kB //经常使用的高速缓冲存储器页面文件大小
Inactive: 295984 kB //不经常使用的高速缓冲存储器文件大小
Active(anon): 381020 kB //活跃的匿名内存
Inactive(anon): 244068 kB //不活跃的匿名内存
Active(file): 174464 kB //活跃的文件使用内存
Inactive(file): 51916 kB //不活跃的文件使用内存
Unevictable: 48 kB //不能被释放的内存页
Mlocked: 48 kB //系统调用 mlock
SwapTotal: 998396 kB //交换空间总内存
SwapFree: 843916 kB //交换空间空闲内存
Dirty: 128 kB //等待被写回到磁盘的
Writeback: 0 kB //正在被写回的
AnonPages: 572776 kB //未映射页的内存/映射到用户空间的非文件页表大小
Mapped: 119816 kB //映射文件内存
Shmem: 50212 kB //已经被分配的共享内存
Slab: 113700 kB //内核数据结构缓存
SReclaimable: 68652 kB //可收回slab内存
SUnreclaim: 45048 kB //不可收回slab内存
KernelStack: 8812 kB //内核消耗的内存
PageTables: 27428 kB //管理内存分页的索引表的大小
NFS_Unstable: 0 kB //不稳定页表的大小
Bounce: 0 kB //在低端内存中分配一个临时buffer作为跳转,把位
于高端内存的缓存数据复制到此处消耗的内存
WritebackTmp: 0 kB //FUSE用于临时写回缓冲区的内存
CommitLimit: 2007148 kB //系统实际可分配内存
Committed_AS: 3567280 kB //系统当前已分配的内存
VmallocTotal: 34359738367 kB //预留的虚拟内存总量
VmallocUsed: 0 kB //已经被使用的虚拟内存
VmallocChunk: 0 kB //可分配的最大的逻辑连续的虚拟内存
HardwareCorrupted: 0 kB //表示“中毒页面”中的内存量
即has failed的内存(通常由ECC标记). ECC代表“纠错码”. ECC memory能够纠正小错误并检测较大错误;
在具有非ECC内存的典型PC上,内存错误未被检测到.如果使用ECC检测到无法纠正的错误(在内存或缓存中,
具体取决于系统的硬件支持),则Linux内核会将相应的页面标记为中毒.
AnonHugePages: 0 kB //匿名大页
【/proc/meminfo的AnonHugePages==所有进程的/proc/<pid>/smaps中AnonHugePages之和】
ShmemHugePages: 0 kB //用于共享内存的大页
ShmemPmdMapped: 0 kB
CmaTotal: 0 kB //连续内存区管理总量
CmaFree: 0 kB //连续内存区管理空闲量
HugePages_Total: 0 //预留HugePages的总个数
HugePages_Free: 0 //池中尚未分配的 HugePages 数量,
真正空闲的页数等于HugePages_Free - HugePages_Rsvd
HugePages_Rsvd: 0 //表示池中已经被应用程序分配但尚未使用的 HugePages 数量
HugePages_Surp: 0 //这个值得意思是当开始配置了20个大页,现在修改配置为16,那么这个参数就会显示为4,一般不修改配置,这个值都是0
Hugepagesize: 2048 kB //大内存页的size
//指直接映射(direct mapping)的内存大小,从代码上来看,值记录管理页表占用的内存,就是描述线性映射空间中,有多个空间分别使用了2M/4K/1G页映射
DirectMap4k: 96128 kB
DirectMap2M: 2000896 kB
DirectMap1G: 0 kB
三、清空cache操作
当你执行 echo 3 > /proc/sys/vm/drop_caches
命令来清空缓存时,它主要会清空文件系统缓存,而不会直接回收应用进程的内存。因此,这个命令不会直接影响上述提到的 active_anon
、inactive_anon
、active_file
和 inactive_file
参数对应的内存值。
具体来说,执行 echo 3 > /proc/sys/vm/drop_caches
命令会清空以下缓存:
-
PageCache:这是文件系统缓存,存储了最近访问的文件数据。
-
dentries 和 inodes 缓存:这些缓存用于存储文件系统的目录项和索引节点。
四、min_free_kbytes说明
设置太低太, 可能会导致内存堆积在file cache中,无法回收,造成内存不足;
设置太高,可能会导致内存浪费,available可用空间变小。
五、确定应用或者内核消耗内存
buff/cache变化不大的时候,available有明显减小大概率说明有内存在泄漏。
如果slab没有一直增大,但是Active一直增大可能是进程内存泄漏。
这里对slab做简要说明,在 Linux 内核中,Slab 是用于管理内核对象缓存的机制,用于分配和释放内核对象的内存。Slab 缓存通常被分为几个部分,包括 Active、Inactive 和 Slab 等。Active Slab 是当前正在使用的 Slab 缓存,而 Inactive Slab 是暂时不再使用的 Slab 缓存,但仍然保留在内存中。
当 Active Slab 增大而 Slab 缓存总量没有增加时,这表明存在内存泄漏的情况。这是因为 Active Slab 的增加意味着内核对象的分配在持续增加,但是如果 Slab 缓存总量没有相应增加,说明这些内核对象并没有被释放,导致内存的持续占用。
如果slab和Active都在增大,说明应用和内核都可能有内存泄漏。
六、内核内存泄露排查方式
打开内核kmemleak配置: CONFIG DEBUG KMEMLEAK=y;通过echo scan>sys/kernel/debug/kmemleak开始扫描内存log,使用echo clear>sys/kernel/debug/kmemleak进行清除,通过看哪个调用栈多,且不断增加,则可能这里就是内存泄露点
另外可使用内核的page owner机制,谁的分配次数或者平方多,可能就是哪个导致了内存泄露
echo scan > /sys/kernel/debug/page_owner
七、内核oom死机参数说明
[ 527.897295] <1>-(1)[9132:TD]CPU: 1 PID: 9132 Comm: TD Tainted: G W O 4.19.98 #1
[ 527.898597] <1>-(1)[9132:TD]Hardware name: mif
[ 527.899575] <1>-(1)[9132:TD]Call trace:
[ 527.900184] <1>-(1)[9132:TD] dump_backtrace+0x0/0x158
[ 527.900942] <1>-(1)[9132:TD] show_stack+0x24/0x30
[ 527.901657] <1>-(1)[9132:TD] dump_stack+0x84/0xac
[ 527.902373] <1>-(1)[9132:TD] dump_header+0x64/0x22c
[ 527.903109] <1>-(1)[9132:TD] oom_kill_process+0xd8/0x2f0
[ 527.903898] <1>-(1)[9132:TD] out_of_memory+0x294/0x2bc
[ 527.904667] <1>-(1)[9132:TD] __alloc_pages_nodemask+0xab4/0xce0
[ 527.905534] <1>-(1)[9132:TD] pagecache_get_page.part.7+0x1ac/0x274
[ 527.906433] <1>-(1)[9132:TD] filemap_fault+0x260/0x564
[ 527.907203] <1>-(1)[9132:TD] __do_fault+0xb8/0x16c
[ 527.907928] <1>-(1)[9132:TD] __handle_mm_fault+0x70c/0xc20
[ 527.908740] <1>-(1)[9132:TD] handle_mm_fault+0x160/0x1c0
[ 527.909532] <1>-(1)[9132:TD] do_page_fault+0x288/0x3f8
[ 527.910301] <1>-(1)[9132:TD] do_translation_fault+0x50/0x88
[ 527.911125] <1>-(1)[9132:TD] do_mem_abort+0x68/0xf8
[ 527.925179] <0>.(0)[9132:TD]Mem-Info:
[ 527.925790] <0>.(0)[9132:TD]active_anon:42191 inactive_anon:57300 isolated_anon:0
[ 527.925790] <0> active_file:71 inactive_file:92 isolated_file:0
[ 527.925790] <0> unevictable:0 dirty:0 writeback:0 unstable:0
[ 527.925790] <0> slab_reclaimable:4986 slab_unreclaimable:15941
[ 527.925790] <0> mapped:3581 shmem:57372 pagetables:1124 bounce:0
[ 527.925790] <0> free:7623 free_pcp:184 free_cma:4
[ 527.930413] <0>.(0)[9132:TD]Node 0 active_anon:168764kB inactive_anon:229200kB active_file:284kB inactive_file:368kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:14324kB dirty:0kB writeback:0kB shmem:229488kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 34816kB writeback_tmp:0kB unstable:0kB all_unreclaimable? no
[ 527.934223] <0>DMA32 free:30492kB min:30400kB low:38000kB high:45600kB active_anon:168764kB inactive_anon:229200kB active_file:500kB inactive_file:20kB unevictable:0kB writepending:0kB present:893684kB managed:655492kB mlocked:0kB kernel_stack:9728kB pagetables:4496kB bounce:0kB free_pcp:668kB local_pcp:28kB free_cma:16kB
[ 527.956422] <0>.(0)[9132:TD]lowmem_reserve[]: 0 0 0
[ 527.957184] <0>DMA32: 514*4kB (UEHC) 495*8kB (UMEHC) 261*16kB (UMEH) 98*32kB (UMEH) 42*64kB (UMEH) 16*128kB (UMEH) 3*256kB (MH) 2*512kB (U) 2*1024kB (UM) 2*2048kB (UM) 1*4096kB (M) = 30096kB
[ 527.959362] <0>.(0)[9132:TD]57685 total pagecache pages
[ 527.960142] <0>.(0)[9132:TD]0 pages in swap cache
[ 527.960856] <0>.(0)[9132:TD]Swap cache stats: add 0, delete 0, find 0/0
[ 527.961810] <0>.(0)[9132:TD]Free swap = 0kB
[ 527.975322] <0>.(0)[9132:TD]Total swap = 0kB
[ 527.976724] <0>.(0)[9132:TD]223421 pages RAM
[ 527.986218] <0>.(0)[9132:TD]0 pages HighMem/MovableOnly
[ 527.987011] <0>.(0)[9132:TD]59548 pages reserved
[ 527.987713] <0>.(0)[9132:TD]4096 pages cma reserved
[ 527.988447] <0>.(0)[9132:TD]0 pages hwpoisoned
[ 527.989127] <0>.(0)[9132:TD]Tasks state (memory values in pages):
[ 527.990014] <0>.(0)[9132:][ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
[ 527.991428] <0>.(0)[9132:][ 2307] 0 2307 1644 137 45056 0 0 some_id1
[ 527.992867] <0>.(0)[9132:][ 2311] 0 2311 428 15 28672 0 0 some_id2
[ 527.994185] <0>.(0)[9132:][ 2734] 0 2734 3681 573 45056 0 -1000 some_socket
active_anon: 当前活跃的匿名内存,即被分配给进程使用的内存,但没有与任何文件关联。
inactive_anon: 当前非活跃的匿名内存,即被分配给进程使用的内存,但目前没有被访问。
active_file: 当前活跃的文件内存,即与文件关联的内存,正在被进程使用。
inactive_file: 当前非活跃的文件内存,即与文件关联的内存,但目前没有被访问,这些页可能仍然在内存中,但由于长时间没有被访问,被标记为非活跃状态。
unevictable: 无法被回收的内存,这些内存页被标记为无法被交换出到磁盘。
isolated(anon): 被隔离的匿名内存,这些内存页被标记为无法与其他进程共享。
isolated(file): 被隔离的文件内存,这些内存页被标记为无法与其他进程共享。
mapped: 映射内存,即被映射到进程地址空间的文件或设备内存。
dirty: 脏页内存,即被修改但尚未写回到磁盘的内存页。
writeback: 正在写回到磁盘的内存页。
shmem: 共享内存,即被多个进程共享的内存。
shmem_thp: 大页面的共享内存。
shmem_pmdmapped: 通过大页面映射的共享内存。
anon_thp: 大页面的匿名内存。
writeback_tmp: 写回临时内存。
unstable: 不稳定的内存。
all_unreclaimable?: 是否所有内存都无法回收。