RTOS内存管理
操作系统提供给用户的另一个重要的功能,就是对你硬件的有限容量内存进行管理,使得你每个任务运行态时,可以最合理地使用硬件平台的内存,这个是内存管理的最基本功能。
(一) “堆”和“栈”
学过微机原理的读者,可能都会知道,在x86架构的机器里面,有两个专门和堆栈管理相关的寄存器,一个叫堆栈段位寄存器SS,另一个叫堆栈指针寄存器SP。我想,这里是大家最早接触堆栈的地方。
但是,细心的读者可能会发现,我在这里的写法是将“堆”和“栈”进行分离,这也就是意味着,这里的“堆”和“栈”并不是指上述里面的“堆栈”。这里的堆栈,说简单点,就是指的操作系统里面的数据结构。我们将英文“Stack”称为“栈区”,将英文“Heap”称为“堆区”。我们再来强调一下,单片机里面或者处理器里面的“堆栈”,指的是一种特殊的存储器,而操作系统里面的“堆”和“栈”,是两种不同的数据结构。
以下例子都是假设在有操作系统基础上。假设,我们用C语言定义一个变量“int a = 0xfe;”,这条语句转到系统操作时,变量a到底存在哪里,并且给它多大的存储区,则由编译器自动分配释放,以上存储的地方,我们称为“栈区” 。另外,存放函数的参数值,局部变量的值等也是存放进入栈中。
而假设,你使用了“malloc”函数去开辟一块内存区,这块存储区,实际上是由一块块连续或者不连续的内存所构成的,其类似于一种链表式的数据存储区,这样的操作就是所谓的在“堆区”开辟内存。
另外,“栈区”存储的变量,系统会在每次使用时进行分配,不用时自动回收,因此为什么有static这种关键词,也是这个原因;而“堆区”的内存,开辟之后,如果不去用,一定要去手动释放它,因为系统不会自动去回收。如果多个任务都动态分配内存,而不去回收,则会容易造成内存溢出,进而产生严重的后果。“堆区”的内存,只有一种情况下是会被自动释放的,也就是强制将系统停止时就释放了。
有了以上知识之后,我们就可以解释操作系统任务的内存分配问题了,所有的操作系统内存管理,都是在系统将处于运行态时,在“堆区”分配给内存一块内存,具体内存的大小,在FreeRTOS里面,由用户自己去设定。这样一来,我们只要分配的合理,我们的任务在任何情况下,都可能分配给运行态的任务最合理的内存大小,因为非运行态的任务可以释放出大量的内存。
(二) 虚拟内存技术
都说Linux的移植性非常广的,你可以在几乎任何带MMU的平台上面移植Linux。这句话似乎有点问题,因为Linux要想移植,首先保证你的平台是带MMU的 。重点是,什么是“MMU”。
“MMU”,内存管理单元(Memory Manage Unit),它是实现“虚拟内存技术”的关键性硬件部件,那么什么是“虚拟内存技术”?为什么要用“虚拟内存技术”?
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。关于虚拟内存的详细说明,可以参考我们后一篇转载的文章。
虚拟内存真正的好处有两点:第一点,避开了应用程序直接访问物理内存,这样的话,即使哪个粗心的程序员忘记释放内存了,系统也只会回收相应的任务,而不会让整个系统奔溃。第二点,可以做到将有限的物理内存,扩展到最高,比如,你的计算机的地址总线是32位的,那就可以将2GB的物理内存,扩展成2^32.。
可惜的是,本来STM32上面跑一个Linux也不是什么大问题,只是由于了MMU的限制,只能遗憾地跑FreeRTOS了,这就是最远的距离。不过前几年,有些内核黑客改写了Linux的内存管理代码,将其MMU限制了,并用软件方式去模拟,命名为uCLinux,只不过,效果实在是不好,因此慢慢没落了。