• 如何划分与组织内存(上)?


    1)本节我们要接触内存了,那我们用最通俗的语言来类比操作系统和内存的关系应该是怎样的?

    • 操作系统是政府,内存是土地。政府必须合理规划好土地,人民才能安居乐业。

    2)既然要规划内存,那我们规划的基本单位有哪两种?

    • 分段和分页

    3)分段和分页有什么区别呢?我们设计操作系统的时候应该怎样选择?

    • 表示方式和状态确定角度:段的大小不一样,用什么数据结构表示不太好表示,并且该段是空闲的还是繁忙的也不太好表示。但是页的大小是固定的,我们用位图的1或者0来表示分配和空闲。

    • 内存碎片的利用:段的长度大小不一,容易产生内存碎片。而页的话是固定的,差生内存碎片的几率小。

    • 从内存和硬盘交换效率考虑:内存不足的时候,会把一部分数据写进磁盘里面去,段的话长短不一样,花费的时间也不一样。硬盘空间分配也会产生碎片,导致系统性能抖动。如果每次交换一个页的话,就没这些问题。

     

    4)页在内存中长什么样?

    • 用分页模型来管理内存,把物理内存分成4KB大小。

      image-20220407191637368

    • 但是要注意一个要点,我们真实的物理内存空间不是连续的,中间可能有空洞,可能是显存之类的。

    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)现在我们内存区和内存页都有了,那我们怎样把他们两联系起来呢?

    • 用一个新的数据结构当胶水把它两联系起来

       
       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;
  • 相关阅读:
    android 的权限
    做android遇到有问题有感
    帮人写的 论文 C语言的 学生管理系统
    android 服务器的 mysql 查询悲剧
    android开发遇到的问题
    想和各位技术高人材交流技术特建了相关的QQ群
    Invalid token '44' in input string
    设置PLSQL Developer访问本机64位Oracle
    SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作……错误:3219……”的解决方法
    C#的JSON开发包 LitJSON
  • 原文地址:https://www.cnblogs.com/YXBLOGXYY/p/16113902.html
Copyright © 2020-2023  润新知