动手写操作系统 -- 内存管理


内存管理,是个永恒的话题。

前面的任务用到的数据要么声明为static或全局变量,放在数据区,要么在函数内部使用,放在任务栈区

但避不了有些情况,在任务运行时需要动态分配/释放内存,即malloc,free。

OK,现在开始搞内存管理。

有个大前提得先说下,我们的系统暂时运行在X86的实模式上,能够访问的内存范围为2^16 = 64K。 (使用远指针除外)

还有现在的内核和任务是放在一起的,即KERNEL.SYS文件大小不到20K,所以还剩下40几K连续内存可以在整个段内访问。

下面将这剩下的内存利用起来,用来给任务提供动态内存分配。

ps: 40多KB内存用来作为动态内存分配,的确很少,这一节的目的是可以让动态内存分配模块成功运行在这段内存上,
    后续会逐步优化,加大可用内存空间。
    再说,很多单片机内置的内存也就几十K,但也能够设计出功能很多的系统。

我是如下设计内存分配的,图中最下面的”内存分配记录Meta区”,是保存每次malloc,free后的已用内存,可用内存的记录。要通过远指针跨段访问。

pic


举例,4次动态分配后,内存使用如下:

char *test1, *test2, *test3, *test4, *test5;
test1 = osMalloc(10);
strcpy(test1, "test1malloc");
test2 = osMalloc(20);
strcpy(test2, "test2malloc");
test3 = osMalloc(10);
strcpy(test3, "test3malloc");
test4 = osMalloc(10);
strcpy(test4, "test4malloc");

pic

然后,两次内存释放,内存使用如下:

osFree(test3);
osFree(test2);

pic

再次申请内存,采用First-Fit策略,如free后的空间足够大,分裂可用空间,内存使用如下:

test5 = osMalloc(12);
strcpy(test5, "test5malloc");

pic


下面是具体实现,我们的FunnyOS系统是用TCC编译的,生成的是EXE可执行文件,好处是可以直接在Windows下运行、调试,

转成BIN文件后通过引导代码载入内存也能直接运行。

代码运行环境:
但是,如何在代码中区别当前是运行在Windows系统中,还是真机环境中呢?
有个方法,如果是真机,使用软件引导的,第511,512个字节的内存固定为0x55,0xAA。
在代码中通过读取这两个字节来判断即可。
获取内存动态分配空间大小:
那如何在代码中获取可用来动态分配内存空间的大小呢?
如果知道了KERNEL.SYS的长度为len,那么可用空间大小 = 64K - len,即可算出。
获取KERNEL.SYS长度可以这样做,我么有个buildimg.c代码,是生成FunnyOS.img的,可以将KERNEL.SYS长度放在FunnyOS.img偏移508,509处。
在系统代码中读取内存地址为(0x7c00+508)处,即可获得KERNEL.SYS大小了。

代码下载:FunnyOS_memory.7z


上篇: 动手写操作系统 -- 任务间通信 下篇: Qemu分析 -- 01 (虚拟CPU的创建与使用)