内存管理是一个系统的重要组成部分。程序的存放和执行都离不开内存。如何高效的对内存进行分配和回收是非常重要的。
如果用户进程直接操作物理地址会有以下的坏处:
1、 用户进程可以直接操作内核对应的内存,破坏内核运行。
2、 用户进程也会破坏其他进程的运行
通过引入逻辑地址,每个进程都拥有单独的逻辑地址范围。
当进程申请内存的时候,会为其分配逻辑地址和物理地址,并将逻辑地址和物理地址做一个映射。
不同进程的逻辑地址可以一样,但是其映射的物理地址是不一样的。
逻辑地址对应的为虚拟内存,物理地址对应的是物理内存。
用户和内核 直接面对的都是虚拟内存。虚拟内存并不是一个真正的存储器,而是一些地址的集合。
CPU中寄存器中存储的是逻辑地址,需要进行映射才能转化为对应的物理地址,然后获取对应的内存。
虚拟内存 分为 内核空间 和 用户空间。
内核空间 就是 操作系统内核使用的空间,对应的物理内存用来存放内核代码、内核数据等。
用户空间 就是 用户进程使用的空间,对应的物理内存用来存放进程对应代码和数据。
1、32位映射详解
物理内存被分为三块:
1、ZONE_DMA
用来存放DMA读取的IO设备的数据,16M
2、ZONE_NORMAL
880M,内核空间可以直接使用的
3、ZONE_HIGHMEM
被称为高端内存,因为内核空间不能直接使用
32位系统,CPU寄存器的长度为43位,所以虚拟地址的最大寻址空间空间为 232,也就是4G。
32位的Linux将这4G虚拟空间按照1:3的比例分别分为 内核空间 和 用户空间。
内核空间映射:
1、直接映射区
896M,内核空间直接映射到对应的ZONE_DMA和ZONE_NORMAL中。为什么叫做直接映射呢? 逻辑地址 直接 减去对应的差值就可以得到对应的物理地址。固定死了。
2、动态映射
为什么要引入动态映射呢?
因为所有物理内存的分配都需要内核程序进行申请,用户进程没有这个权限。所以内核空间一定要能映射到所有的物理内存地址。
那么如果都采用直接映射的话,1G大小逻辑地址的内核空间只能映射1G大小的物理内存。
所以引入了动态映射,动态映射就是 内核空间的逻辑地址可以映射到 物理内存中的ZONE_HIGHMEM(高端内存)中的任何一个地址,并且在对应的物理内存使用完之后,可以再映射其他物理内存地址。
动态映射分为三种
1、动态内存映射: 使用完对应的物理内存后,就可以映射其他物理内存了。
2、永久内存映射: 一个虚拟地址只能映射一个物理地址。如果需要映射其他物理地址,需要解绑。
3、固定内存映射: 只能被某些特定的函数来调用引用物理地址。
动态内存映射和直接映射的区别
动态映射和直接映射的区别就是逻辑地址到物理地址的转化规则。
直接映射
直接映射的规则是死的,一个逻辑地址对应的物理地址是固定的。通过逻辑地址加或者减去一个数,就可以得到对应的物理地址。
动态映射
动态映射是动态的绑定,每个逻辑地址对应的物理地址是动态的,通过页表进行查询
用户空间映射:
用户空间 采用 动态映射,每个虚拟地址可以被映射到一个物理地址,映射到ZONE_HIGHMEM。
为什么用户空间不采用直接映射呢?
因为物理内存是多个进程所有的,每个进程都有一个用户空间。如果采用直接映射的话,对应的物理地址是会冲突的。其用户空间的逻辑地址大小都为3G,所以存在逻辑地址相同,但是对应的物理地址不同。需要通过页表来转化,一个进程会对应一个页表。
Linux采用分页管理,将物理内存分为若干个4KB的page(页),页是分配和回收的基本单位。
对于内存中的这若干个page,怎么分配和回收呢?怎么能够快速的分配和回收呢?
伙伴算法用于分配大内存。
伙伴算法 通过一个链表数组,数组中的链表对应存放的分别为大小为1、2、4、8个页的页框。
分配:
假如需要5个页,就到8个页对应的链表,也就是数组中下标为3的链表,查看是否存在对应的页框,如果存在,就将其取下分配。
如果不存在,就找16个页对应的链表,如果存在大小为16个页的页框,就将其一分为二,将一个分配,然后将另一个加入到下标为3的链表中。
释放
当释放的时候,查看其同伴是否空闲,如果空闲就将其合并,然后继续查看合并后的同伴是否空闲。
如果不空闲,就将其加入到对应的链表上。
伙伴算法的缺点:
伙伴算法分配的最小单位为 1个页,4k,当分配小数据的时候,就会造成资源浪费。
这就引入了slab算法
slab维护了三个链表,链表上的节点对应的是一个页 page 4k
1、空闲链表
page还未被使用
2、部分空闲链表
页中部分被占用,还有一些内存空闲
3、用尽链表
页被完全使用
分配:
首先查看部分空闲链表是否可以分配,如果部分空闲链表中的一个页再分配之后,被占满了,就将其加入到用尽链表中。
如果部分空闲链表不能分配,就选择空闲链表,并将对应的页插入到部分空闲链表中。
释放:
如果释放之后,页为空了,就将其加入到空闲链表中
如果释放之后,页不为空,就将其加入到部分空闲链表中
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_40276626/article/details/120468106
内容来源于网络,如有侵权,请联系作者删除!