linux内存从0到1学习笔记(九,内存优化调试之三-内存拆解)---持续更新(代码片段)

高桐@BILL 高桐@BILL     2022-12-03     211

关键词:

写在前面

我们在日常的工作当中需要各种手段来调试内存,尤其是在内存泄漏的情况下,我们需要一种手段来统计内存的使用去向,以确定内存使用不合理的方向。或者物理内存有限的情况下,需要对内存进行优化,也需要通过一些手段达到对内存的拆解。

一、free命令

free命令用于显示系统中剩余物理内存大小、已使用物理内存大小、交换空间大小和内核使用的缓冲区和缓存大小等信息。这些信息通过解析/proc/meminfo而来,样式如下:

  • total:分两行,分别表示内存总大小,和swap空间总大小;
  • used:已使用物理内存大小,(计算方式 used = total - free - buffers - cache)
  • free:未使用物理内存大小,(来源于/proc/meminfo中的MemFree和SwapFree)
  • shared:tmpfs使用的内存(并非百分百),(来源于/proc/meminfo中的Shmem)
  • buff/cache:buffers和cache的总和
  • buffers:内核缓冲使用的内存(来源于/proc/meminfo中的Buffers)
  • cache:页缓存和slabs使用的内存(来源于/proc/meminfo中的Cached 和SReclaimable)

二、/proc/meminfo

该部分英文原版摘自于《proc(5) - Linux manual page》;其条目并不一定与实际使用的meminfo,可作为参考;

meminfo用于统计当前系统内存使用情况;

2.1 MemTotal %lu

表示实际可用内存总大小(即物理内存 - 保留位 - kernel二进制代码)。

2.2 MemFree %lu

LowFree和HihtFree总大小,这个在我实际使用的linux版本中并没有LowFree和HighFree,因此需要进一步调研学习。我把它理解为系统中完全没有被分配的内存;

2.3 MemAvailable %lu (Linux 3.14引入)

表示可供启动新的应用程序所使用的的内存大小;不包括交换空间;

2.4 Buffers %lu

表示为原始磁盘块所使用的的临时存储区域,不超过20M。有人理解为是用来给文件做缓冲大小,这部分需要再确认下。

2.5 Cached %lu

内存缓存(in-memory cache),用于缓存从磁盘读取文件。不包括交换缓存。

<buffers + cached的值就是可以使用的磁盘高速缓存的大小。>

<buffers + cached = Active(file) + Inactive(file) + Shmem>。

2.6 SwapCached %lu

内存使用交换空间交换出来的内存,但仍然被存放在swapfile中。(如果内存压力比较大的时候,这些内存页不需要再被换出,因为他们已经在交换文件中存在,这就解放了I/O。)

当该交换空间上的其他数据被换出,或是换入内存中的数据被改写,则交换缓存上的记录会被清空。

2.7 Active %lu

表示经常使用的和非必要不会被回收的内存大小,等于Active(anon) + Active(file)的和。

2.8 Inactive %lu

表示不经常使用的和某种原因更容易被回收的内存大小,等于Inactive(anon) + Inactive(file)的和。

2.9 Active(anon) %lu (Linux 2.6.28引入)

表示经常使用的和非必要不会被回收的匿名内存大小。

<匿名内存就是进程中在堆内存上分配的内存,是用malloc分配的内存。>

2.10 Inactive(anon) %lu (Linux 2.6.28引入)

表示不经常使用的和某种原因更容易被回收的匿名内存大小。

2.11 Active(file) %lu (Linux 2.6.28引入)

表示经常使用的和非必要不会被回收的file-backed内存大小,与匿名页的区别在于物理内存的内容是否与物理磁盘上的文件相关联。

<file-backed内存为磁盘高速缓存的内存空间和“文件映射(将物理磁盘上的文件内容与用户进程的逻辑地址直接关联)”的内存空间,其中的内容与物理磁盘上的文件相对应。Linux内核中使用4类LRU表来分别记录对应的这4类内存页,内存页一般以4K为一页。>

2.12 Inactive(file) %lu (Linux 2.6.28引入)

表示不经常使用的和某种原因更容易被回收的file-backed内存大小,与匿名页的区别在于物理内存的内容是否与物理磁盘上的文件相关联。

2.13 Unevictable %lu (Linux 2.6.28引入)(需打开CONFIG_UNEVICTABLE_LRU内核配置项)

表示不能被释放的内存页,这些内存页不能放在LRU表中,而是记录到Unevictable表中。

2.14 Mlocked %lu (Linux 2.6.28 引入)

2.15 HighTotal %lu (Linux 2.6.19引入, 需使能CONFIG_HIGHMEM配置)  

Hightmem所使用的的内存大小。目前所参与开发的版本中大多数的64G内存,这部分已经不常用了。

2.16 HighFree %lu (Linux 2.6.19引入, 需使能CONFIG_HIGHMEM配置)

Hightmem可用的内存大小。

2.17 LowTotal %lu (Linux 2.6.19引入, 配置项CONFIG_HIGHMEM)  

LowMemeory所使用的的内存大小。

2.18 LowFree %lu (Linux 2.6.19引入, 配置项CONFIG_HIGHMEM)  

LowMmeory中可用的内存大小;

2.19 MmapCopy %lu (Linux 2.6.29引入, 配置项CONFIG_MMU)

待归档

2.20 SwapTotal %lu

交换空间的总大小。

2.21 SwapFree %lu

当前交换空间的剩余容量。

2.22 Dirty %lu

脏数据,在磁盘缓冲区中尚未写入物理磁盘的内存大小

2.23 Writeback %lu

在磁盘缓冲区中要被写入物理磁盘的内存大小

2.24 AnonPages %lu (Linux 2.6.18引入)

映射到用户空间页表的匿名页。

Linux内核中存在一个rmap(reverse mapping)机制,负责管理匿名内存中每一个物理内存页映射到哪个进程的哪个逻辑地址这样的信息。 这个rmap中记录的内存页总和就是AnonPages的值。

2.25 Mapped %lu

通过mmap(2)进行文件映射占用的内存大小;

2.26 Shmem %lu (Linux 2.6.32引入)

tmpfs所使用的内存。

tmpfs即利用物理内存来提供RAM磁盘的功能。在tmpfs上保存文件时,文件系统会暂时将它们保存到磁盘高速缓存上,因此它是属于磁盘高速缓存对应的"buffers+cached"一类。 但是由于磁盘上并没有与之对应的内容,因此它并记录在File-backed内存对应的LRU列表上,而是记录在匿名内存的LRU表上。 这就是 buffers + cached = Active(file) + Inactive(file) + Shmem 公式的由来

2.27 KReclaimable %lu (Linux 4.20引入)

内核分配并在内存紧张的时候的内核将要尝试回收的内存大小。包括SReclaimable 和其他注册了shrinker函数分配的内存。

2.28 Slab %lu

slab分配器分配的内存。

Slab分配器针对一些经常分配并释放的对象(如进程描述符)统计各种数据类型的汇总信息,然后为每种数据类型创建多个由多个内存页组成的Slab(这些Slab组成一个Slab列表)。 再在Slab内部划分成一个个相应数据类型的对象。

当内核要使用某种类型的数据结构时,就从对应的slab列表中分配一个对象出去,而当要释放时,将其重新保存在Slab列表中,从而避免内存碎片。

当可供使用的对象不足时,会使用空闲的内存页来创建并添加新的Slab到对应对象的Slab列表中。 相反,若Slab中所有对象都被内核回收,即所有对象都未使用时,根据需要也可以回收Slab,释放成空闲内存。

2.29 SReclaimable %lu (Linux 2.6.19引入)

Slab分配的内存的一部分,这部分可能会被回收,就像缓存一样。

2.30 SUnreclaim %lu (Linux 2.6.19引入)

Slab分配的内存的一部分,在内存进展的情况下也不会被回收。

2.31 KernelStack %lu (Linux 2.6.32引入)

内核栈使用的内存大小

2.32 PageTables %lu (Linux 2.6.18引入)

PageTables就是页表,用于存储各个用户进程的逻辑地址和物理地址的变换关系,它本身也消耗内存空间。

2.33 Quicklists %lu (Linux 2.6.27引入 CONFIG_QUICKLIST配置项)

待归档

2.34 NFS_Unstable %lu (since Linux 2.6.18)

不稳定页表的大小

2.35 Bounce %lu (since Linux 2.6.18)

在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处消耗的内存

2.36 WritebackTmp %lu (since Linux 2.6.26)

FUSE用于临时写回缓冲区的内存

2.37 CommitLimit %lu (since Linux 2.6.10)

系统实际可分配内存总量

2.38 Committed_AS %lu

当前已分配的内存总量

2.39 VmallocTotal %lu

Linux使用内存时,除了使用Slab中配置的对象外,还能直接将空闲内存页映射到逻辑地址上。

这个容量指的是,理论上内核内部可以用来映射的逻辑地址的范围。这个值非常大,但并非实际使用的物理内存

2.40 VmallocUsed %lu(Linux
                     4.4已不再使用)

Linux将空闲内存页映射到逻辑地址上的容量。

值得说明的是,这个容量除了物理内存上所作的映射外,也包括诸如视频卡这样的外部设备内存所作的映射,这类映射叫做"ioremap"

我们可以通过 /proc/vmallocainfo 查看VmallocUsed中包含内存区域的详情

2.41 VmallocChunk %lu(Linux
                     4.4已不再使用)

从Linux4.4版本开始,VmallocChunk字段不再使用

2.42 HardwareCorrupted %lu (Linux 2.6.32引入,CONFIG_MEMORY_FAILURE配置项)

待归档

2.43 LazyFree %lu (Linux 4.12引入)

madvise(2)标记使用的内存大小 ,实际上我没有理解这个是干嘛用的,待进一步调研。(MADV_FREE)
                     .

2.44 AnonHugePages %lu (Linux 2.6.38引入)(CONFIG_TRANSPARENT_HUGEPAGE配置项)  

表示透明巨页面支持的内存大小。

2.45 ShmemHugePages %lu (Linux 4.8引入) (CONFIG_TRANSPARENT_HUGEPAGE 配置项)

通过shmem和tmpfs(5)分配的巨页的内存大小

2.46 ShmemPmdMapped %lu (since Linux 4.8)(CONFIG_TRANSPARENT_HUGEPAGE配置项)

映射到用户空间巨页的共享内存大小。

2.47 CmaTotal %lu (Linux 3.1引入 CONFIG_CMA配置项)

DMA/CMA (Contiguous Memory Allocator) 预留内存总大小

2.48 CmaFree %lu (Linux 3.1引入 CONFIG_CMA配置项)

剩余(Contiguous Memory Allocator) 内存大小。

2.49 HugePages_Total %lu(CONFIG_HUGETLB_PAGE 配置项)

支持的巨页内存总数量

2.50 HugePages_Free %lu(CONFIG_HUGETLB_PAGE配置项)

剩余还未分配的巨页个数

2.51 HugePages_Rsvd %lu (Linux 2.6.17引入)(CONFIG_HUGETLB_PAGE配置项)

已经被分配预留但是还没有使用的巨页数目。

2.52 HugePages_Surp %lu (Linux 2.6.24引入)(CONFIG_HUGETLB_PAGE配置项)

HugePages_Total减去/proc/sys/vm/nr_hugepages中的值

2.53 Hugepagesize %lu (CONFIG_HUGETLB_PAGE配置项)

每单位的巨页的大小,常常为2M。

三、/proc/zoneinfo

四、/proc/buddyinfo

五、/sys/kernel/debug/dma-buf/bufinfo

六、/proc/slabinfo

七、/proc/vmallocinfo

写在最后

这些调试手段并不是最有效,最完善的调试手段。那么我们还有一种调试手段就是page owner。page owner会跟踪统计所有内存分配的去向,及其调用栈。我们单独成篇来介绍这个终极大杀器。

linux内存从0到1学习笔记(9.10内存优化调试之panic_on_oom介绍

通过配置/proc/sys/vm/panic_on_oom文件节点可以使能或禁用out-of-memory的panic。接下来我分享下在对该节点功能及代码架构的学习笔记;一,简介文件节点路径:/proc/sys/vm/panic_on_oom相关变量:vm.panic_on_oom该节点有三个值,分别是0,1,2... 查看详情

linux内存从0到1学习笔记(9.7内存优化调试之page_owner内存分配堆栈详解)---更新中

...序,解析。最终可以确认那些任务或进程占用了多少内存。无论是正常分配的,还是内存黑洞的内存,我们都可以通过解析pageowner拆分出来。那么接下来我们对pageowner中的内存分配堆栈进行一个详细的介绍和分析。以... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之二-内存空间的建立)(代码片段)

在使用load_elf_binary装在一个ELF二进制文件时,将创建进程的地址空间。Linux下的exec系统调用该函数来加载ELF文件。linux_mainline-5.17.0/fs/binfmt_elf.c823staticintload_elf_binary(structlinux_binprm*bprm)824825 structfile*interpreter= 查看详情

linux内存从0到1学习笔记(6.8,物理内存初始化之buddy伙伴系统)

写在前面在linux启动的那一刻,内存管理就已经开始了。在内核中,实现物理内存管理的allocator包括:初始化阶段物理内存管理memblock连续物理内存管理buddy非连续物理内存管理vmallocallocator小块物理内存管理slaballocator在系统初始... 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之三-内存映射)(代码片段)

...通常C标准库只提供了一个函数,由应用程序用来创建内存映射,接下来该函数调用在内部转换为适合于体系结构的系统调用mmap和mmap2。可使用munmap系统调用删除映射。一、内存映射简介        mmap完成的是将物理内... 查看详情

linux内存从0到1学习笔记(6.3,物理内存初始化之内存基本数据结构初始化)(代码片段)

写在前面这部分主要介绍,bootmem_init()内存基本数据结构初始化,如内存节点,内存域。linux_mainline-5.17.0/arch/arm64/mm/init.c321void__initbootmem_init(void)322323 unsignedlongmin,max;324//获取最大最小页号;325 min=PFN_UP(memblock_start_of_DRAM( 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(8.14dma-buf内存调试二bufinfo介绍)--更新中(代码片段)

bufinfo是我们调试dmabuf使用的一个非常有效的debug信息。因此我们需要了解下它的由来以及记录的关键信息。并且根据场景需要来对跟踪的信息进行调整和完善,以满足我们的调试需要。一,bufinfo的生成首先在内核初始化子系统... 查看详情

linux内存从0到1学习笔记(8.14dma-buf内存调试二bufinfo介绍)--更新中(代码片段)

bufinfo是我们调试dmabuf使用的一个非常有效的debug信息。因此我们需要了解下它的由来以及记录的关键信息。并且根据场景需要来对跟踪的信息进行调整和完善,以满足我们的调试需要。一,bufinfo的生成首先在内核初始化子系统... 查看详情

linux内存从0到1学习笔记(10.1bugsshooter之cma配置过小导致页迁移繁忙而内存申请失败)

...程tombstone中的CALLSTACK,确认为_M_allocate_bucket进行bucket内存分配时发生异常;2.2kernel或串口日志alloc_congit_range:(xxx,xxx)PFNsbusy;cm 查看详情

linux内存从0到1学习笔记(五,内存分类)

一、内存类型ARMv8架构处理器定义了两种类型的内存类型,分别是普通内存(NormalMemory)和设备内存(DeviceMemory)。二、普通内存        普通内存对应MT_NORMAL属性;        普通内存由于其弱一致... 查看详情

linux内存从0到1学习笔记(二,arm64物理内存)

写在前面我们先通过一张图来里哦啊接下ARM处理器的内存管理架构;2.1ARM处理器的内存管理架构ARM处理器内核:是指ARM架构的CPU中间的核心芯片,由单晶硅制成,用来完成所有的计算、接受/存储命令、处理数据等... 查看详情

linux内存从0到1学习笔记(四,tlb)

...、TLB简介        Kernel初始化的时候,会在初始化内存中创建页表;而处理器读取指令和数据的时候需要首先通过MMU查表得到物理地址,然后在访问物理地址读取指令或数据。MMU查表过程汇中需要4次访问内存,... 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.9可恢复硬件页面错误的含义)

...起的页面错误显然会阻碍加速器上运行的任务,通常需要内存分配来解决错误。但是,不允许内存分配来控制DMA围栏的完成,这意味着使用可恢复页面错误的任何工作负载都不能使用DMA围栏进行同步,而必须改用由用户空间控制... 查看详情