内存管理,是个永恒的话题。
前面的任务用到的数据要么声明为static或全局变量,放在数据区,要么在函数内部使用,放在任务栈区。
但避不了有些情况,在任务运行时需要动态分配/释放内存,即malloc,free。
OK,现在开始搞内存管理。
有个大前提得先说下,我们的系统暂时运行在X86的实模式上,能够访问的内存范围为2^16 = 64K。 (使用远指针除外)
还有现在的内核和任务是放在一起的,即KERNEL.SYS文件大小不到20K,所以还剩下40几K连续内存可以在整个段内访问。
下面将这剩下的内存利用起来,用来给任务提供动态内存分配。
ps: 40多KB内存用来作为动态内存分配,的确很少,这一节的目的是可以让动态内存分配模块成功运行在这段内存上, 后续会逐步优化,加大可用内存空间。 再说,很多单片机内置的内存也就几十K,但也能够设计出功能很多的系统。
我是如下设计内存分配的,图中最下面的”内存分配记录Meta区”,是保存每次malloc,free后的已用内存,可用内存的记录。要通过远指针跨段访问。
举例,4次动态分配后,内存使用如下:
然后,两次内存释放,内存使用如下:
再次申请内存,采用First-Fit策略,如free后的空间足够大,分裂可用空间,内存使用如下:
下面是具体实现,我们的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