一、linux内存泛解

发布于:2024-05-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

地址空间

逻辑地址经过段机制转换成线性地址,线性地址经过页机制转换成物理地址
linux采用虚拟内存管理,进程都有各自的地址空间这个空间整体是块大小为4G的线性虚拟空间用户看到的都是虚拟地址,而非实际的物理地址,这既能保护操作系统(用户不能直接访问物理内存),又能使用比实际物理内存更大的虚拟内存空间
4G虚拟内存分为用户空间和内核空间。用户空间从0到3G (0xC0000000),内核空间占据3G到4G,用户进程一般不能访问内核空间,但是当进行系统调用(在内核态执行)时可以访问到内核空间。用户空间会随进程切换而变化,内核空间由内核映射固定不变,都有对应的页表。进程的用户空间相互独立,互不干扰
64位系统的内核空间和用户空间都是128T,分别占据整个内存空间的最高和最低处,剩余的中间部分是未定义的。

在这里插入图片描述
如图是一个x86虚拟地址计算物理地址的过程:首先是分段机制计算出线性地址,再利用分页机制计算出物理地址

  • TI为0表示该段在全局描述符(GDT),TI为1表示在局部描述符(LDT),通过查找段描述符可以找到段基址
  • 把段描述符中取得的段基址加上虚拟地址(偏移量) 上形成一个线性地址
  • 线性地址的高10位索引目录,线性地址的中间10位索引页表,得到物理页面基地址
  • 物理页面基地址加上线性地址的底12位,得到最终的物理地址

在这里插入图片描述
多级页表解决空间上的问题,但是虚拟地址到物理地址的转换增加了寄到转换的工序,转换速率降低,时间变大
MMU查询页表过程,根据程序局部性原理,增加程序最小访问的小片cache(TLB),增加命中率,提高访问速度,当页表内容变化时需要清除防映射出错
在这里插入图片描述

NODE、ZONE、PAGE基本概念

node——非一致性内存访问 NUMA(Non-Uniform Memory Access),内存划分为各个node,访问一个node花费的时间取决于CPU离这个node的距离,CPU内部有一个本地node,访问速度比其他node快。而一致性内存访问 UMA(Uniform Memory Access)或SMP(Symmetric Multi-Process)对称多处理器,访问内存时间都一样,相当于只有一个node。

zone——整个物理内存划分为几个区域,每个区域含义不同。

page——物理页,用struct page表示,比如4k大小的页,这个页内的区域为page frame,编号为page frame num(pfn)。系统启动时,内核将整个struct page映射到虚拟地址空间vmemmap区域,故vmemmap为页基地址,vmemmap+pfn即为struct page对应地址。内核支持的内存模型包含
CONFIG_FLATMEM(平坦内存模型)、CONFIG_DISCONTIGMEM(不连续内存模型)和CONFIG_SPARSEMEM_VMEMMAP(稀疏的内存模型)

zoned page frame allocator——分区页框分配器,用来管理物理内存,内核或进程需要申请页框分配器来获取内存页框,不需要时必须释放内存页框,如果无法分配足够页框,需要按规则从其他管理区获取,按规定要求依次获取:[ZONE_HIGHMEM ->] ZONE_NORMAL -> ZONE_DMA。见组织方式
在这里插入图片描述
内存碎片化
内部碎片化:分配给用户空间未使用的部分内存
外部碎片化:系统无法使用的非连续小内存块
解决外部碎片化,使用伙伴系统,解决内部碎片化,使用slab算法

为了避免内存碎片化,有如下迁移类型在linux系统中

MIGRATE_TYPE Short descrition
MIGRATE_UNMOVABLE Page can’t move,used be kernel/driver
MIGRATE_RECLAIMABLE Temp used memory,can be discard
MIGRATE_MOVABLE Memory with MMU mapping,can be move to any where
MIGRATE_RESERVE Reserved memory,not used
MIGRATE_CMA For CMA(Contiguous Memory Allocator) use
MIGRATE_ISOLATE Temp isolated area, can’t allocated memory from this type

伙伴系统

order负责管理这些零散的page到对应的order 20~210中
0代表都是零散的1page,page大小是4k,也就是说order0链表中存放的都是N个4K连续的内存块地址
1代表 2^1个连续地址的page,可以理解为order1链表中存放的都是2个连续的page 放在一个,有N个 2个连续的page,可以理解为有N个8k的连续内存块
10就是代表2^10个连续地址的page,可以理解为order10链表中存放的都是1024个连续的page,可以理解为有N个 4x1024k大小的连续内存块
page有不同的类型,所以每一个order又有多个链表,每一种order类型的链表连续块大小是一样的,但是page的类型不一样
zone的作用:负责把新空出来的page合并到最大的内存,比如 新出了一个4k的page,先在order0中找,没有没有连续的,如果有连续的,就合并,放到order1中,以此类推,一直合并到最高的内存中
在这里插入图片描述
Buddy–伙伴系统算法,把所有空闲页框分组为11个块链表(order),每个链表分别包含大小为1、2、4、8、16、…、1024个连续页框的页框块,最大可以申请1024个连续页框,对应4MB的连续内存,每个页框的第一个页框的物理地址是该块大小的整数倍

假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个页框的链表中找,找到了则将页框块分为2个256个页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页框的链表查找,如果仍然没有,则返回错误。页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。Buddy算法一直在对页框做拆开合并拆开合并的动作,可以查看/proc/buddyinfo某页框剩余空闲块个数
在这里插入图片描述

用户空间使用malloc/new/mmap去分配内存,但是page不会马上分配给他,直到访问内存的时候去分配

除了CMA,其他所有内存分配API都是调用__alloc_pages_nodemask从伙伴系统分配内存

Slab分配器
伙伴系统以页分配,slab以字节分配,减少对伙伴系统分配算法的调用次数(频繁分配和回收必然会导致内存碎片化,难以找到大块连续的可用内存),可以很好地利用硬件缓存提高访问速度。slab中的对象分配和销毁使用kmem_cache_alloc与kmem_cache_free
Vmalloc
最小分配一个page,并且分配的页面不保证是连续的,因为alloc_page多次分配单个页面
CMA
reserved的一块内存,用于分配连续的大块内存,预留给驱动使用,当设备驱动不用时,内存管理系统将该区域用于分配和管理可移动页面类型;当设备驱动使用时,此时已经分配的页面需要进行迁移,又用于连续内存内配;其用法与DMA子系统结合在一起充当DMA的后端。
在这里插入图片描述
在这里插入图片描述

用户空间内存分区

在这里插入图片描述

分配与回收

(1) 内存分配与申请
当程序启动时,终端进程调用exec函数将可执行文件载入内存,此时代码段、stack段都是通过mmap函数映射到内存空间,堆则要根据是否有在堆上申请内存来决定是否映射,exec执行之后,此时并未真正开始执行进程,而是将CPU控制权交给了动态链接库装载器,由它来将该进程需要的动态链接库装载进内存;之后才开始进程的执行。

如果用户态申请大内存时,是直接调用mmap分配内存,此时返回给用户态的内存还是虚拟内存,直到第一次访问返回的内存时,才真正进行内存的分配;当进程在用户态通过调用free释放内存时,如果这块内存是通过mmap分配,则调用munmap直接返回给系统;否则内存是先返回给内存分配器,然后由内存分配器统一返还给系统。

(2) 系统内存回收

  • 手动内存回收:
#1 free pagecache
#2 free dentries and inodes
#3 free pagecache,dentries and inodes
echo 1/2/3 > /proc/sys/vm/drop_caches

如果pagecache中有脏数据时,操作drop_caches是不能释放的,必须通过sync命令将脏数据刷新到磁盘,才能通过操作drop_caches释放pagecache.
drop_caches能释放的就是当磁盘读取文件时缓存页以及某个进程将某个文件映射到内存之后,进程退出,这是映射文件的缓存页如果没有被引用,也是可以被释放的。

  • 自动内存回收
    内核有一个kswapd (内核线程,用于页面回收) 会周期性的检查内存使用情况,如果发现空闲内存低于page_low,则kswapd会对lru_list前4个lru队列进行扫描,在活跃链表中查找不活跃的页,并添加不活跃链表;然后再遍历不活跃链表,逐个进行后手释放出32个页,直到free page数量达到page_high水平;针对不同的页,回收方式也不一样。

当内存水平低于某个极限阈值时,会直接发出内存回收,原理跟kswapd一样,但是这次回收力度更大,需要回收更多的内存

如果申请的内存大于系统剩余的内存时,就会产生oom (out of memory)杀死进程,释放内存。


网站公告

今日签到

点亮在社区的每一天
去签到