1)本节我们要接触内存了,那我们用最通俗的语言来类比操作系统和内存的关系应该是怎样的?
- 操作系统是政府,内存是土地。政府必须合理规划好土地,人民才能安居乐业。
2)既然要规划内存,那我们规划的基本单位有哪两种?
- 分段和分页
3)分段和分页有什么区别呢?我们设计操作系统的时候应该怎样选择?
- 表示方式和状态确定角度:段的大小不一样,用什么数据结构表示不太好表示,并且该段是空闲的还是繁忙的也不太好表示。但是页的大小是固定的,我们用位图的1或者0来表示分配和空闲。
- 内存碎片的利用:段的长度大小不一,容易产生内存碎片。而页的话是固定的,差生内存碎片的几率小。
- 从内存和硬盘交换效率考虑:内存不足的时候,会把一部分数据写进磁盘里面去,段的话长短不一样,花费的时间也不一样。硬盘空间分配也会产生碎片,导致系统性能抖动。如果每次交换一个页的话,就没这些问题。
4)页在内存中长什么样?
- 用分页模型来管理内存,把物理内存分成4KB大小。
- 但是要注意一个要点,我们真实的物理内存空间不是连续的,中间可能有空洞,可能是显存之类的。
5)现在我们知道了页长什么样,那怎样来表示它呢?
- 可以考虑用一个位图或者整型数组。位值为1表示页已分配,位值为0表示页空闲。整型数组中的值来表示页的状态。那么分配释放的话其实就是数组的删除和插入。但是这个是最低效的方式
- 上面的方案低效,因为它仅仅保存是内存分配还是空闲的信息,其它像页的状态,页的地址,页的类型我们都不知道,看下来的话我们可以使用C语言的结构体来表示。
//内存空间地址描述符标志
typedef struct s_MSADFLGS
{
u32_t mf_olkty:2; //挂入链表的类型
u32_t mf_lstty:1; //是否挂入链表
u32_t mf_mocty:2; //分配类型,被谁占用了,内核还是应用或者空闲
u32_t mf_marty:3; //属于哪个区
u32_t mf_uindx:24; //分配计数
}__attribute__((packed)) msadflgs_t;
//物理地址和标志
typedef struct s_PHYADRFLGS
{
u64_t paf_alloc:1; //分配位
u64_t paf_shared:1; //共享位
u64_t paf_swap:1; //交换位
u64_t paf_cache:1; //缓存位
u64_t paf_kmap:1; //映射位
u64_t paf_lock:1; //锁定位
u64_t paf_dirty:1; //脏位
u64_t paf_busy:1; //忙位
u64_t paf_rv2:4; //保留位
u64_t paf_padrs:52; //页物理地址位
}__attribute__((packed)) phyadrflgs_t;
//内存空间地址描述符
typedef struct s_MSADSC
{
list_h_t md_list; //链表
spinlock_t md_lock; //保护自身的自旋锁
msadflgs_t md_indxflgs; //内存空间地址描述符标志
phyadrflgs_t md_phyadrs; //物理地址和标志
void* md_odlink; //相邻且相同大小msadsc的指针
}__attribute__((packed)) msadsc_t;
6)我们的内存只有一个区吗?
- 有很多的区域,一些区域放硬件,一些区域放内核,一些区域放个人的应用,就像一个城市有不同的区一样,各有各的特色和使命。注意这个内存区是逻辑上划分的,也就是不是实际存在的。
7)我们要如何表示一个内存区呢?
- 和先前物理内存页面一样,我们需要定义一个数据结构,来表示一个内存区的开始地址和结束地址,里面有多少个物理页面,已经分配了多少个物理页面,剩下多少等等。
#define MA_TYPE_HWAD 1
#define MA_TYPE_KRNL 2
#define MA_TYPE_PROC 3
#define MA_HWAD_LSTART 0
#define MA_HWAD_LSZ 0x2000000
#define MA_HWAD_LEND (MA_HWAD_LSTART+MA_HWAD_LSZ-1)
#define MA_KRNL_LSTART 0x2000000
#define MA_KRNL_LSZ (0x40000000-0x2000000)
#define MA_KRNL_LEND (MA_KRNL_LSTART+MA_KRNL_LSZ-1)
#define MA_PROC_LSTART 0x40000000
#define MA_PROC_LSZ (0xffffffff-0x40000000)
#define MA_PROC_LEND (MA_PROC_LSTART+MA_PROC_LSZ)
typedef struct s_MEMAREA
{
list_h_t ma_list; //内存区自身的链表
spinlock_t ma_lock; //保护内存区的自旋锁
uint_t ma_stus; //内存区的状态
uint_t ma_flgs; //内存区的标志
uint_t ma_type; //内存区的类型
sem_t ma_sem; //内存区的信号量
wait_l_head_t ma_waitlst; //内存区的等待队列
uint_t ma_maxpages; //内存区总的页面数
uint_t ma_allocpages; //内存区分配的页面数
uint_t ma_freepages; //内存区空闲的页面数
uint_t ma_resvpages; //内存区保留的页面数
uint_t ma_horizline; //内存区分配时的水位线
adr_t ma_logicstart; //内存区开始地址
adr_t ma_logicend; //内存区结束地址
uint_t ma_logicsz; //内存区大小
//还有一些结构我们这里不关心。后面才会用到
}memarea_t;
8)现在我们内存区和内存页都有了,那我们怎样把他们两联系起来呢?
- 用一个新的数据结构当胶水把它两联系起来
标签:MA,组织,u64,划分,uint,内存,ma,define From: https://blog.51cto.com/u_15810109/5719089
typedef struct s_BAFHLST
{
spinlock_t af_lock; //保护自身结构的自旋锁
u32_t af_stus; //状态
uint_t af_oder; //页面数的位移量
uint_t af_oderpnr; //oder对应的页面数比如 oder为2那就是1<<2=4
uint_t af_fobjnr; //多少个空闲msadsc_t结构,即空闲页面
uint_t af_mobjnr; //此结构的msadsc_t结构总数,即此结构总页面
uint_t af_alcindx; //此结构的分配计数
uint_t af_freindx; //此结构的释放计数
list_h_t af_frelst; //挂载此结构的空闲msadsc_t结构
list_h_t af_alclst; //挂载此结构已经分配的msadsc_t结构
}bafhlst_t;