一步步写操作系统(四) 内存管理
来源:互联网 发布:删除excel中重复数据 编辑:程序博客网 时间:2024/06/15 14:59
一步步写操作系统(四)
4.内存管理
在弄清楚了boot以及asm和c语言之间的调用关系以后,写底层就已经没有任何问题了。一些机制,比如中断、调用门、异常等等,都是可以通过这一个简单的语言调用关系来书写出一个完整的功能。在我看来,现在不忙讨论这些机制的问题,因为这些太超前。不妨先来讨论一下和编程更接近的问题,也就是内存分配。这个重要但是会比那些机制更简单。
之前在帖子中提到使用C语言的struct来实现C++的class,我们的内存管理就是要用这种方法来进行编写。
首先,应该清楚,内存管理需要什么。不管是物理内存还是虚拟内存、单页内存还是分页内存,管理内存无外乎就两个变量:起始地址和偏移量。在内存管理中其实地址就是基地址,偏移量就是内存可用大小。我们在成熟的操作系统中就可以模拟这两个变量,那就是char型数组。
以下是可以在成熟操作系统比如linux或者windows上运行的内存管理程序。
首先来看一个基本类,这是在使用C语言的struct来实现C++的class中提到的经过改版的基本类:
MultiLink.h
// MultiLink.h//#pragma once#include <stdlib.h>#define __SUPER(B, T, E) \ union {\ B super; \ struct {\ Template##B (T, E)\ }; \ }//////////////////////////////////////////////////////////typedef struct MultiLinkElement {#define MultiLinkElementTemplate(T)\ int linkcount;\ T ** prev;\ T ** next;\ void(*final)(T *that);\ T * (*free)(T * that);\ void(*clear)(T * that);#define TemplateMultiLinkElement(T, E) MultiLinkElementTemplate(struct T) TemplateMultiLinkElement(MultiLinkElement, NULL)}MultiLinkElement;void MultiLinkElement_clear(MultiLinkElement * that) { int i; for (i = 0; i < that->linkcount; i++) { that->prev[i] = NULL; that->next[i] = NULL; }}MultiLinkElement * MultiLinkElement_free(MultiLinkElement * that) { int i; for (i = 0; i < that->linkcount; i++) { if (that->prev[i] != NULL || that->next[i] != NULL) { return that; } } return NULL;}void _MultiLinkElement(MultiLinkElement * that, int linkcount) { that->linkcount = linkcount; that->clear = MultiLinkElement_clear; that->free = MultiLinkElement_free; that->final = NULL; that->clear(that);}//////////////////////////////////////////////////////////typedef struct MultiLinkBase {#define MultiLinkBaseTemplate(T, E) \ int linkcount;\ int linkindex;\ E * link;\ void(*insertLink)(T * that, E * link, E * before, E * after); \ E * (*removeLink)(T * that, E * link); \ E * (*get)(T * that, int index); \ E * (*prev)(T *that, E * link); \ E * (*next)(T *that, E * link);#define TemplateMultiLinkBase(T, E) MultiLinkBaseTemplate(struct T, struct E) TemplateMultiLinkBase(MultiLinkBase, MultiLinkElement)}MultiLinkBase;MultiLinkElement * MultiLinkBase_removeLink(MultiLinkBase * that, MultiLinkElement * link) { MultiLinkElement * before, * after; if (link == NULL) { return NULL; } if (that->linkindex < 0) { return NULL; } if (link->prev[that->linkindex] == NULL || link->next[that->linkindex] == NULL) { return NULL; } before = link->prev[that->linkindex]; after = link->next[that->linkindex]; before->next[that->linkindex] = after; after->prev[that->linkindex] = before; link->prev[that->linkindex] = NULL; link->next[that->linkindex] = NULL; if (that->link == link) { that->link = after; } if (that->link == link) { that->link = NULL; } that->linkcount = that->linkcount - 1; return link;}MultiLinkElement * MultiLinkBase_get(MultiLinkBase * that, int index) { MultiLinkElement * temp; if (that->link == NULL) { return NULL; } temp = that->link; do { temp = temp->next[that->linkindex]; } while (temp && temp != that->link && --index); return temp;}void MultiLinkBase_insertLink(MultiLinkBase * that, MultiLinkElement * link, MultiLinkElement * before, MultiLinkElement * after) { MultiLinkElement * _link; if (link == NULL) { return; } if (that->link == NULL) { that->link = link; that->link->prev[that->linkindex] = link; that->link->next[that->linkindex] = link; that->linkcount = that->linkcount + 1; return; } else { _link = NULL; if (before == that->link) { _link = link; } if (before == NULL && after == NULL) { before = that->link; after = that->link->prev[that->linkindex]; } else if (before == NULL) { before = after->next[that->linkindex]; } else if (after == NULL) { after = before->prev[that->linkindex]; } else /* before != NULL && after != NULL*/ { if (before->prev[that->linkindex] != after || after->next[that->linkindex] != before) { return; } } if (before == NULL || after == NULL || before->prev[that->linkindex] == NULL || after->next[that->linkindex] == NULL) { return; } link->prev[that->linkindex] = after; link->next[that->linkindex] = before; after->next[that->linkindex] = link; before->prev[that->linkindex] = link; if (_link) { that->link = _link; } that->linkcount = that->linkcount + 1; }}MultiLinkElement * MultiLinkBase_prev(MultiLinkBase *that, MultiLinkElement * link) { if (link == NULL) { return NULL; } return link->prev[that->linkindex];}MultiLinkElement * MultiLinkBase_next(MultiLinkBase *that, MultiLinkElement * link) { if (link == NULL) { return NULL; } return link->next[that->linkindex];}void _MultiLinkBase(MultiLinkBase * that, int linkindex) { that->linkcount = 0; that->linkindex = linkindex; that->link = NULL; that->insertLink = MultiLinkBase_insertLink; that->prev = MultiLinkBase_prev; that->next = MultiLinkBase_next; that->removeLink = MultiLinkBase_removeLink; that->get = MultiLinkBase_get;}////////////////////////////////////////////////////////typedef unsigned char UMAP;#define MAP_SHIFT 8#define POOL_MAX 10#define MAP_MAX POOL_MAX / MAP_SHIFT + 1#define MAP_MASK 0xFFtypedef struct ElementPool {#define ElementPoolTemplate(T, E)\ E * pool;\ UMAP * map;\ int size;\ int msize;\ int count;\ E * (*at)(T * that, int index);\ E * (*get)(T * that);\ void(*back)(T * that, E * o);#define TemplateElementPool(T, E) ElementPoolTemplate(struct T, struct E) TemplateElementPool(ElementPool, MultiLinkElement)}ElementPool;MultiLinkElement * ElementPool_at(ElementPool * that, int index) { // Inherit struct must override this function // because the size of the type of pool is different // Note: in this kind of inherit, be careful when // using arry of specified type, but there's no // need to worry about using pointer of the type // e.g. MultiLinkElement has pointer array : // prev and next, and there's no need to // override any get/set function in inherit struct return &that->pool[index];}MultiLinkElement * ElementPool_get(ElementPool * that) { int i, j, index; for (i = 0, index = 0; i < that->msize && index < that->size; i++, index += MAP_SHIFT) { if (that->map[i] & MAP_MASK) { for (j = 0; j < MAP_SHIFT && index < that->size; j++, index++) { if (that->map[i] & (0x01 << j)) { that->map[i] &= ~(0x01 << j); return that->at(that, index); } } } } return NULL;}void ElementPool_back(ElementPool * that, MultiLinkElement * o){ int i, j, index; if (o == NULL) { return; } for (index = 0; index < that->size; index++) { if (that->at(that, index) == o) { i = index / MAP_MASK; j = index - i * MAP_MASK; that->map[i] |= (0x01 << j); return; } }}void _ElementPool(ElementPool * that, MultiLinkElement * pool, UMAP * map, int size) { int i; if (size > POOL_MAX) { size = POOL_MAX; } that->pool = pool; that->map = map; that->size = size; that->at = ElementPool_at; that->get = ElementPool_get; that->back = ElementPool_back; that->msize = size / MAP_SHIFT + 1; if (that->msize > MAP_MAX) { that->msize = MAP_MAX; } for (i = 0; i < that->msize; i++) { that->map[i] = MAP_MASK; }}//////////////////////////////////////////////////////////
MultiLinkElement是基本的元素类,提供基本的数据存储基类,后期可以继承变为内存管理单元、任务管理单元等。然后MultiLinkBase是一个MultiLinkElement的容器类,用于管理元素类链表。ElementPool类是一个管理元素类的内存池,这个池就是是分配在kernel中的一个元素类数组,当需要创建一个元素类时由Pool来提供,因为在内存管理中是没有new和delete函数的。
接下来是内存单元类,继承自MultiLinkElement类:
MemStat.h
// MemStat.h//#pragma once#include "MultiLink.h"typedef int MEM_SIZE;typedef char * MEM_ADDR;typedef int MEM_STAT;#define MEM_OCCUPPIED 1#define MEM_AVAILABLE 0typedef struct MemStat MemStat;struct MemStat { __SUPER(MultiLinkElement, MemStat, NULL); MemStat * _prev[2]; MemStat * _next[2]; MEM_STAT stat; MEM_SIZE size; MEM_SIZE block; MEM_ADDR addr; void(*set)(MemStat * that, int size); void (*split)(MemStat * that, MemStat * mem); void (*merge)(MemStat * that, MemStat * mem);};void MemStat_set(MemStat * that, int size) { // 4 k block int div = size / 0x1000; int del = size - div * 0x1000; that->block = del ? (div + 1) * 0x1000 : div * 0x1000; that->size = size;}void MemStat_final(MemStat * that){ //printf("MemStat final.");}void MemStat_split(MemStat * that, MemStat * mem) { that->block -= mem->block; that->size -= mem->block; mem->addr = that->addr + that->block;}void MemStat_merge(MemStat * that, MemStat * mem) { that->block += mem->block; that->size += mem->block;}MemStat * _MemStat(MemStat * that, MEM_ADDR addr, MEM_SIZE size) { that->prev = that->_prev; that->next = that->_next; _MultiLinkElement(&that->super, 2); that->split = MemStat_split; that->merge = MemStat_merge; that->set = MemStat_set; that->final = MemStat_final; that->set(that, size); return that;}
然后是内存池类,继承自ElementPool类:
MemPool.h
// MemPool.h//#pragma once#include "MultiLink.h"#include "MemStat.h"typedef struct MemPool MemPool;struct MemPool { __SUPER(ElementPool, MemPool, MemStat);};MemStat * MemPool_at(MemPool * that, int index) { return &that->pool[index];}void _MemPool(MemPool * that, MemStat * pool, UMAP * map, int size) { _ElementPool(&that->super, (MultiLinkElement *)pool, map, size); that->at = MemPool_at;}
最后是内存管理类,继承自MultiLinkBase类。这个类集合了上面两个MemStat和MemPool类,提供基本的池管理和内存管理:
MemMan.h
// MemMan.h//#pragma once#include "MultiLink.h"#include "MemStat.h"#include "MemPool.h"typedef struct MemMan MemMan;struct MemMan { __SUPER(MultiLinkBase, MemMan, MemStat); MemStat pool[POOL_MAX]; UMAP map[MAP_MAX]; MemPool memPool; void(*add)(MemMan * that, MemStat * link); MemStat * (*getAddr)(MemMan * that, MEM_ADDR addr, int stat); MEM_ADDR(*realloc)(MemMan * that, MEM_ADDR addr, MEM_SIZE size); MEM_ADDR(*alloc)(MemMan * that, MEM_SIZE size); void (*free)(MemMan * that, MEM_ADDR addr); void (*merge)(MemMan * that, MemStat * start, MemStat * end); void (*split)(MemMan * that, MemStat * tango, MemStat * item); MemStat * (*remove)(MemMan * that, MemStat * link);};void MemMan_add(MemMan * that, MemStat * link) { that->insertLink(that, link, NULL, NULL);}MemStat * MemMan_getAddr(MemMan * that, MEM_ADDR addr, int stat) { MemStat * mem; if (that->link == NULL) { return NULL; } mem = that->link; do { if (mem->stat == stat && mem->addr == addr) { return mem; } mem = that->next(that, mem); } while (mem && mem != that->link); return NULL;}MEM_ADDR MemMan_realloc(MemMan * that, MEM_ADDR addr, MEM_SIZE size) { MemStat * mem; MemStat * item; MemStat * prev, *next; int mark; if (that->link == NULL) { return (MEM_ADDR)NULL; } mem = that->getAddr(that, addr, 1); if (mem == NULL) { return (MEM_ADDR)NULL; } //MemStat * item = new MemStat(0, size); item = that->memPool.get(&that->memPool); if (item == NULL) { return (MEM_ADDR)NULL; } item->set(item, size); if (mem->block == item->block) { mem->set(mem, size); //delete item; that->remove(that, item); return addr; } if (mem->block > item->block) { that->split(that, mem, item); mem->stat = MEM_AVAILABLE; item->stat = MEM_OCCUPPIED; prev = that->prev(that, mem); if (mem != that->link && prev->stat == MEM_AVAILABLE) { that->merge(that, prev, mem); } return item->addr; } prev = that->prev(that, mem); next = that->next(that, mem); mark = 0; if (item != that->link && prev->stat == MEM_AVAILABLE) { if (mem->block + prev->block >= item->block) { mark = -1; if (next != that->link && next->stat == MEM_AVAILABLE) { if (mem->block + next->block >= item->block) { // next and prev which is the minimum if (next->block < prev->block) { mark = 1; } } } } } else if (next != that->link && next->stat == MEM_AVAILABLE) { if (mem->block + next->block >= item->block) { mark = 1; } } if (mark > 0) { item->set(item, next->block - item->block + mem->block); if (item->block > 0) { that->split(that, next, item); } else { //delete item; that->remove(that, item); } that->merge(that, mem, next); return addr; } else if (mark < 0) { item->set(item, item->block - mem->block); that->split(that, prev, item); that->merge(that, item, mem); item->stat = MEM_OCCUPPIED; item->set(item, size); return item->addr; } else { that->free(that, addr); return that->alloc(that, size); }}MEM_ADDR MemMan_alloc(MemMan * that, MEM_SIZE size) { MemStat * item; MemStat * mem ; MemStat * min; if (that->link == NULL) { return (MEM_ADDR)NULL; } //MemStat * item = new MemStat(0, size); item = that->memPool.get(&that->memPool); if (item == NULL) { return (MEM_ADDR)NULL; } item->set(item, size); mem = that->link; min = NULL; do { if (mem->stat == MEM_AVAILABLE && mem->block >= item->block) { if (min == NULL || min->block > mem->block) { min = mem; } } mem = that->next(that, mem); } while (mem && mem != that->link); if (min) { that->split(that, min, item); item->stat = MEM_OCCUPPIED; return item->addr; } return (MEM_ADDR)NULL;}void MemMan_free(MemMan * that, MEM_ADDR addr) { MemStat * mem = that->getAddr(that, addr, MEM_OCCUPPIED); MemStat * prev; MemStat * next; if (mem == NULL) { return; } mem->stat = MEM_AVAILABLE; prev = that->prev(that, mem); next = that->next(that, mem); if (mem != that->link && prev->stat == MEM_AVAILABLE) { that->merge(that, prev, mem); } else if (next != that->link && next->stat == MEM_AVAILABLE) { that->merge(that, mem, next); } if (mem != that->link && prev->stat == MEM_AVAILABLE && next != that->link && next->stat == MEM_AVAILABLE) { that->merge(that, prev, next); }}void MemMan_merge(MemMan * that, MemStat * start, MemStat * end) { if (that->link == NULL) { return; } if (start == NULL || end == NULL) { return; } if (that->next(that, start) != end) { return; } start->merge(start, end); //delete that->remove(that, end); that->remove(that, end);}MemStat * MemMan_remove(MemMan * that, MemStat * link) { that->removeLink(that, link); if (link->free(link) == NULL) { that->memPool.back(&that->memPool, link); } return link;}void MemMan_split(MemMan * that, MemStat * tango, MemStat * item) { if (that->link == NULL) { return; } if (tango == NULL || item == NULL) { return; } that->insertLink(that, item, NULL, tango); if (tango->block == item->block) { item->addr = tango->addr; //delete that->removeLink(that, tango); that->removeLink(that, tango); return; } tango->split(tango, item);}MemMan * _MemMan(MemMan * that, int index) { int i; _MultiLinkBase(&that->super, index); that->add = MemMan_add; that->alloc = MemMan_alloc; that->free = MemMan_free; that->realloc = MemMan_realloc; that->getAddr = MemMan_getAddr; that->merge = MemMan_merge; that->split = MemMan_split; that->remove = MemMan_remove; for (i = 0; i < POOL_MAX; i++) { _MemStat(&that->pool[i], 0, 0); } _MemPool(&that->memPool, that->pool, that->map, POOL_MAX); return that;}
从MemMan类的代码可以看到,该管理类不仅继承自MultiLinkBase容器类,并且管理这MemStat和MemPool两个类,其中提供了MemStat数组供MemPool类使用,并且保存有MemPool需要的一个Map表,这个Map表是标记MemStat数组使用和未使用情况的映射表。另外注意的一点就是,在MemPool中,即使使用MemStat数组指针传递给其内含的pool指针,该指针也会被转化为基类MultiLinkElement指针,因此,使用这个指针索引MemStat时,不能直接基类提供的at函数更不能直接使用[]进行索引,而要在MemPool类中重写at函数进行索引,否则基类的at函数或者[]索引,计算的是MultiLInkElement的大小,而不是MemStat的大小,导致偏移出错。
在这里我们可以看到,这样的操作非常繁琐,但是,在完成底层书写以后,内存管理留出来的接口使用起来就很简单了,外层只需要初始化MemMan类,即可对内存进行管理:
Memory.c
#include <stdlib.h>#include <stdio.h>#include <string.h>#include "MemMan.h"char * memory;MemMan memMan;int main() { _MemMan(&memMan, 1); memory = (char *)malloc(0x10000000);//使用现存操作系统提供的malloc函数为内存管理提供一个模拟的内存(返回值为起始地址,大小为分配的大小) memset(memory, 0, 0x10000000); MemStat * mem = memMan.memPool.get(&memMan.memPool); mem->addr = (MEM_ADDR)memory; mem->set(mem, 0x10000000); memMan.add(&memMan, mem); MEM_ADDR addr = memMan.alloc(&memMan, 1000); if (addr) { memcpy((char *)addr, "alloc", 10); } int i; for (i = 0; i < memMan.linkcount; i ++) { mem = memMan.get(&memMan, i); printf( "d: %10X, s: %10u, b: %10u, s: %d, v: %s\n", mem->addr, mem->size, mem->block, mem->stat, (char *)mem->addr); } printf("========================\n"); addr = memMan.realloc(&memMan, addr, 10000); if (addr) { memcpy((char *)addr, "RE-alloc", 10); } for (i = 0; i < memMan.linkcount; i ++) { mem = memMan.get(&memMan, i); printf( "d: %10X, s: %10u, b: %10u, s: %d, v: %s\n", mem->addr, mem->size, mem->block, mem->stat, (char *)mem->addr); } printf("========================\n"); addr = memMan.realloc(&memMan, addr, 10); if (addr) { memcpy((char *)addr, "RE-alloc", 10); } for (i = 0; i < memMan.linkcount; i ++) { mem = memMan.get(&memMan, i); printf( "d: %10X, s: %10u, b: %10u, s: %d, v: %s\n", mem->addr, mem->size, mem->block, mem->stat, (char *)mem->addr); } printf("========================\n"); memMan.free(&memMan, addr); for (i = 0; i < memMan.linkcount; i ++) { mem = memMan.get(&memMan, i); printf( "d: %10X, s: %10u, b: %10u, s: %d, v: %s\n", mem->addr, mem->size, mem->block, mem->stat, (char *)mem->addr); } printf("========================\n"); for (i = 0; i < POOL_MAX; i++) { addr = memMan.alloc(&memMan, 100); if (!addr) { printf("alloc error: @%d\n", i); } } for (i = 0; i < memMan.linkcount; i ++) { mem = memMan.get(&memMan, i); printf( "d: %10X, s: %10u, b: %10u, s: %d, v: %s\n", mem->addr, mem->size, mem->block, mem->stat, (char *)mem->addr); } printf("========================\n"); free(memory);}
同样,在我们自己写的操作系统中,也使用上面的方法对内存进行管理。
只是在内存起始地址、可用大小上,有一些出入。自己的操作系统中,需要避免使用kernel所在内存,并且要检测内存大小。
本代码,以及完整的可运行的操作系统代码已经更新到GitHub和Gitee,在Test/Memory_Linux下面有上面的代码,以供测试。
GITHUB: https://github.com/stophin/NanoOS
GITEE: https://gitee.com/stophin/NanoOS
- 一步步写操作系统(四) 内存管理
- 操作系统——内存管理(四)
- 一步步写操作系统(一) BOOT启动
- 一步步写操作系统(五) 任务切换
- 通过Linux理解操作系统(四):内存管理(上)
- Linux操作系统基础知识之四:内存管理
- 自己动手写操作系统(四)
- 操作系统--------内存管理(2)
- 操作系统------内存管理(3)
- 操作系统 内存管理(一)
- 操作系统 内存管理(二)
- 操作系统:内存管理(概念)
- 操作系统:内存管理(概念)
- 操作系统:内存管理(一)
- Linux操作系统基础(四)保护模式内存管理(2)
- 读《自己动手写操作系统》(四)
- C#内存管理(四)
- WinCE内存管理(四)
- python3爬虫(8):异常处理以及代理的使用
- Android 使用 WindowManager 实现悬浮窗监控 cpu 温度
- Android Studio中两个模拟器互发短信的解决方案
- Android Binder机制
- JavaScriptBOM对象
- 一步步写操作系统(四) 内存管理
- Oracle之merge经典案例
- idea软件如何创建多级包
- Leetcode 322 & 518
- PageHelper的使用
- 开源协议的理解
- Largest prime factor(素数筛选法)
- Python图像处理的基本操作(一)
- java使用UDP协议进行服务器客户端通信