【搜索微信公众号】百万年薪运维工程师手札
让我们一同为了理想前进
Linux内核内存布局
64位Linux一般使用48位来标识虚拟地址空间,45位标识物理地址。通过命令cat /proc/cpuinfo可以查看地址大小。其实也可以用lscpu查看,两者查看的内容来源是一致的。
CPUINFO信息
processor : 0
vendor_id : GenuineIntel //CPU制造商
cpu family : 6 //CPU产品代号
model : 154 //CPU属于其系列中的哪个代号
model name : 12th Gen Intel(R) Core(TM) i7-1280P //CPU的名称,编号,主频
stepping : 3 //CPU属于制作更新版本
microcode : 0x421
cpu MHz : 1996.800 //CPU实际使用的主频
cache size : 24576 KB //CPU二级缓存
physical id : 0 //单个CPU的标号
siblings : 4 //单个CPU逻辑物理合数
core id : 0 //当前物理核在其所处的CPU中编号
cpu cores : 4 //逻辑核所在CPU的物理核数
apicid : 0 //用来区分不同逻辑核的编号
bogomips : 3993.60 //系统内核启动时测算的CPU速度
clflush size : 64 //每次刷新缓存的大小单位
cache_alignment : 64 //缓存地址空间对齐单位
address sizes : 45 bits physical, 48 bits virtual //可以访问的地址空间的位数
MEMINFO信息
[root@TEST ~]# cat /proc/meminfo
MemTotal: 3488048 kB //所有可用内存空间大小
MemFree: 3012560 kB //系统还没有使用内存
MemAvailable: 2948008 kB //系统真正可用内存
Buffers: 20424 kB //专用用来给块设备做缓存的内存
Cached: 203764 kB //分配给文件缓冲区的内存
SwapCached: 0 kB
Active: 167832 kB // 使用高速缓存存储器页面文件大小
Inactive: 122852 kB //没有经常使用的高速缓存存储器大小
Active(anon): 77860 kB //活跃的匿名内存
Inactive(anon): 7324 kB //不活跃的匿名内存
Active(file): 89972 kB //活跃的文件使用内存
Inactive(file): 115528 kB //不活跃的文件使用内存
Unevictable: 11044 kB //不能被释放的内存页
Mlocked: 11044 kB //系统调用mlock允许程序在物理内存上锁住部分地址空间
SwapTotal: 3145724 kB
SwapFree: 3145724 kB
Dirty: 0 kB //等待被刷入磁盘的数据(脏页)
Writeback: 0 kB //正在被写入的数据
AnonPages: 75508 kB //未映射页的内存/映射到用户空间的非文件页表大小
Mapped: 58840 kB //映射文件内存
Shmem: 9352 kB //已经被分配的共享内存
Slab: 78704 kB //内存数据结构缓存大小
SReclaimable: 37528 kB //可回收slab大小
CommitLimit: 4889748 kB //系统实际可以分配内存
Committed_AS: 362004 kB //系统当前已经分配的内存
VmallocTotal: 34359738367 kB //预留虚拟内存的总量
VmallocUsed: 0 kB //已经被使用的虚拟内存
VmallocChunk: 0 kB //可分配的最大逻辑地址连续的虚拟内存
Linux动态内存分配接口
Linux内核动态内存分配通过系统接口实现
alloc_pages/__get_free_page: 以页为单位分配
vmalloc: 以字节为单位分配虚拟地址连续的内存块
kmalloc:以字节为单位分配物理地址连续的内存块,以slab为中心,
同样也可以通过vmalloc分配的内存进行统计输出
ARM64架构采用48为物理寻址方式,最大可寻找256TB的物理地址空间,虚拟地址同样也支持48位寻址。
Linux内核将上述地址分为:用户空间和内核空间
用户空间地址为0x0000 0000 0000 0000 到0x0000 FFFF FFFF FFFF
内核空间地址为0xFFFF 0000 0000 0000 到0xFFFF FFFF FFFF FFFF
Linux内核内存布局
Linux内核内存布局(ARM64架构处理器内存分布)
KASAN(影子区): 它是一个动态检测内存错误的工具,原理利用额外的内存标记可用内存状态,将1/8区域用作影子区
modules: 内核模块使用的虚拟地址空间
vmalloc: vmalloc函数使用的虚拟地址空间
.text: 代码段
.init: 模块初始化数据
.data: 代表数据段
.bss: 静态内存分配段
fixed: 固定映射区域
PCI I/O:针对PCI设备的I/O地址空间
vmemmap: 内存的物理地址,如果不连续的话,就会存在内存空洞(稀疏内存), vmmemmap就是用来存放稀疏内存的page结构体的数据的虚拟地址空间
memory: 线性映射区域
我们可以通过内存布局打印输出(Linux内核初始化完成后,整体布局稳定,通过Vexpress平台输出即可):
通过start_kernel函数->mm_init->mem_init->分配内存初始化
堆管理
堆是进程中主要用于动态分配变量和数据的内存区域,堆的管理对应程序员不是直接可见的。malloc和内核之间的经典接口是brk系统调用,负责扩展/收缩堆。
堆是一个连续的内存区域,在扩展时自下至上增长。其中mm_struct结构,包含堆在虚拟地址空间中的起始和当前结束地址(start_brk和brk)
内存描述mm_struct结构体当中,有堆起始地址和结束地址的成员
brk系统调用内核源码
Linux系统有两个方法可以调用创建堆(heap)
brk()是系统调用,实际是设置进程数段的结束地址,将数据段的结束地址向高地址移动
mmap()向操作系统申请一段虚拟地址空间(使用映射到某个文件),当不用此空间来映射到某个文件时,这块空间称为匿名空间,可以用来作为堆空间
per-CPU计数器
引入用来加速SMP系统上计数器操作,内核代码如下: