在软件行业,模块化编程早已深入人心,通过模块的划分能有效地减小软件系统的复杂度,模块化其实就是将系统“分而治之”的方法。在嵌入式系统中,每一个模块存在初始化函数相对比较的普遍,但是并不是每一个模块都存在一个终止化函数,相反,有可能整个系统根本就没有终止化函数。之所以出现这种现象,这与嵌入式系统的特点有关。与桌面系统上的软件不同的是,由于整个嵌入式设备就只有一个应用软件在运行,因此,对软件的关闭或重启大都是通过开、关设备电源或按下重启按钮这种“粗暴的”方式来完成的。久而久之大家都就习惯了,进而将设计模块的终止化函数当作了多余。

    从完整性的角度来看,一个模块如果存在初始化的过程,就理应提供终止化函数以实现模块的终止,当然设计终止化函数不应当只是为了感觉更好,而应当还有其它的目的和内涵,那是什么呢?为每一个模块设计终止化函数的目的是为了提供一种“优雅地”关机或重启系统的手段,而其进一步的内涵是,通过这种方式将提供一个检测系统资源泄漏的机会。

    现在,让我们以内存资源为例来分析采用优雅关机的好处。在嵌入式系统中,由于不考虑各模块终止化函数的设计,造成从堆中分配出来的具有全局生命周期的内存在系统系统关闭时不存在释放操作。如此一来,在系统的关闭过程中不容易发现内存泄露问题,因为分不清哪些内存是系统运行期间必须永久持有的(即非内存泄漏),哪些又是动态分配但没有释放的(即内存泄漏)。假设使用内存的每个模块都提供了终止化函数,且系统提供一种方式(比如通过命令行)以触发优雅关机流程,其结果就是导致每一个模块的终止化函数被有序地调用。显然,那些具有全局生命周期的内存在每一个模块的终止化函数中都应进行释放操作,最终在优雅关机的过程中也会被释放。进一步,在内存管理模块的终止化函数中(注意:前面讲的是使用内存的模块,而现在讲的是管理内存的模块),可以设计成检测当前是否仍有内存被分配出去了,如果有,则很有可能存在内存泄漏。如果内存管理模块被设计成能记录所有已分配出去内存的详细信息的话(指内存的分配是在哪一个文件的哪一行),在发现仍有内存没有释放的话,将这些相关信息通过某种方式输出将有助于发现内存泄漏点。当然,这里有一个很重要的前提假设,那就是在优雅关机的过程中使用内存的模块的终止化函数必须在内存管理模块的终止化函数之前被调用,这一点可以通过一定的模块管理轻松做到。

    内存资源可以通过优雅关机的方式发现泄漏,其它的资源同样可以采用这一方法发现泄漏。比如,在定时器管理模块的终止化函数中可以检查是否所有的定时器都已回收了,等等。有了优雅关机的方式以后,并不妨碍我们采用“粗暴的”方式进行系统的关闭或重启,但它的存在却提供了一种需要时能被使用以辅助发现潜在的资源泄漏问题。

    设计模块的终止化函数需要一点工作量,但这点工作量是可以承受的,而且也应当承担它。与潜在的资源泄漏相比,花上这些时间是值得的。另外,设计得好的系统,不只是简单地提供初始化和终止化函数,还应当站在整个系统的角度设计一定的机制去管理系统中模块的初始化和终止化。