基于嵌入式系统设计中查找内存丢失的策略方案
可以将分配长度不同,但类型相关(如可变长度的字符数组)的内存块链接起来。
C++通过使我们重载或删除按类基(per-class basis)而使得这种方法更加简便易行。尽管这是一种有效的方法,但这里我仍然不会采用这种方法,因为我更倾向采用适合C语言环境的技术。
分配位置
有时,位置信息比类型信息更为有效。幸而我们能够灵活地使用宏定义,从而无须更换标记即可选择这些信息。
==========================
#define mMalloc(size_t size)
mMallocLineNo(size, __LINE__,
__FILE__)
=========================
mMallocLineNo()函数是程序清单1中函数mMalloc()的变异。现在我们期望像程序清单3那样存储行号和文件名信息,为保持额外信息,结构BlockEntry将具有如下形式:
=========================
typedef struct
{
void * addr;
size_t size;
int line;
char * file;
} BlockEntry;
==========================
通过为每个内存块存储行号和文件名,就能精确地定位任何分配的内存块。可以为所有特定长度的表项设计一个输出行号和文件名为mDisplayLocatiON()的函数,这样就能轻易地识别出长度可疑的内存块的来源。
再次回到表1,可能我们会担心长度为44的内存块。为了更多地了解这些内存的来源,可以在函数main()的末尾添加如下代码:
========================
mDisplayLocation(44);
=======================
这能将行44输出50遍。
=======================
line = 162, file = listing2.c
=======================
这清晰地表明内存块在函数growForever()中分配。
可变的长度
某些内存分配的长度可以发生急剧变化,例如:
==========================
char *p = malloc(strlen(nAME)+1);
==========================
是分配一块足以存储字符串名和字符串截止符的内存的通用方法。在嵌入式系统中,不会经常对字符串和文件进行操作;数据结构的分配则不是这样,例如:
==========================
Motor *m = malloc(sizeof(Motor));
==========================
如果假定Motor为存储结构,那么上述分配将总是得到相同长度的内存块,在上面描述的函数中,将在输出中更简便地识别出这些内存块。
在分配可变长度内存块时,可以行号和文件名的组合为核心计算内存分配的计数。示例中,我们存储了行号和文件名,但打印的总数则取决于长度。通过行号和文件名的聚合分配将有助于在相同的位置将所有的分配组合起来,而不管分配的长度如何。某些情况下,即便可变的长度不成问题,这样的分析仍然能带给我们更多的启发。
内存表
任何含有内存丢失的代码都将导致这里给出的内存表不断增大,而且并非所有的丢失都能像growForever()示例那样清晰无误地进行识别。即便采用其它技术进行丢失检测和消除,这些输出表仍将有助于确定丢失是否已被消除。
这里给出的循环并不处理可变的输入数据。在实际项目中,通常插入一些调用(如仿真键盘敲击序列的调用)以模拟输入。在实际系统中,还必须创建一些适当的输入。除非自己希望改变代码,否则完全无须访问导致内存丢失的代码段。因此,这里的示例或许向大家提供了一个良好的开端,但任何内存丢失仍然需要进行一些检测。
丢失 策略 方案 内存 查找 嵌入式 系统 设计 基于 相关文章:
- AVR内部EEPROM数据丢失问题的原因与解决方案(08-16)
- C8051Fxxx程序丢失问题及预防措施分析(07-29)
- uClinux进程调度器的实现分析(04-13)
- 嵌入式系统安全性对攻击状况和防卫策略的概述和分析(02-21)
- 嵌入式操作系统任务切换方法对比分析(07-02)
- 记录仪实时多任务调度策略的研究(07-16)