新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 基于嵌入式系统设计中查找内存丢失的策略方案

基于嵌入式系统设计中查找内存丢失的策略方案

作者:时间:2012-03-13来源:网络收藏

过程中,要利用数组保存分配的每一个块记录,在块释放的同时,也将该记录从数组中删除。在主循环的每次迭代之后,分配的块的总数目将打印出来。理想情况下,要按类型对这些内存块排序,但指向malloc()和free()的调用则不包含任何类型信息。内存分配的大小是最好的标识,因此成为工程师需要记录的信息。此外,还需要存储分配的内存块地址信息,这样,当调用释放函数时,就可以方便地定位或删除块记录。

本文引用地址:http://www.eepw.com.cn/article/149447.htm

在添加和删除块记录时,还需要跟踪每种大小的内存块数目,程序的列表1给出了实现上述功能的代码。

随着内存块的分配和释放,数组:
  =======================

  typedef struct

  {

  void * address;

  size_t size;

  } BlockEntry;

  ======================

跟踪当前存在的所有内存块。另一数组则跟踪当前存在的每种大小的内存块总数:

  ======================

  typedef struct

  {

  int count;

  size_t size;

  } Counter;

  ======================

函数mDisplayTable()允许我们在每次主循环结束时输出结果。如果printf()不可用,则可利用调试器中断并检验数组的内容。

上述代码还必须使NUM_SIZES 和 NUM_BLOCKS足够大,以处理中的大量内存分配;但也不能太大,从而导致在系统运行之前就已耗尽所有的RAM。

输出

快速地浏览代码,可以注意到结构类型Sensor的长度定义如下:

  =======================

  typedef struct

  {

  int offset;

  int gain;

  char name[10];

  } Sensor;

  ======================

假定int为32位数据,那么Sensor的长度将为18(4+4+10),但在测试中,结果表明为20。编译器可以在存储结构的数据成员之间自由地添加填充,以将对齐强制设定为一个字边界。特殊情况下,每个字段开始于一个已存在的字边界,那么为什么还需要填充呢?填充添加在存储结构的最末端,如果声明了一个数组Sensor,那么该数组的所有成员(而不仅仅是第一个成员)将会进行字对齐。根据处理器的不同,字对齐的速度将有所差异,有时这些编译器将提供可根据速度选择字对齐长度的切换开关。在任何情形下,最好不要根据源代码的定义对存储结构的长度作任何假设。

下面考察当使用这些函数时,将得到何种类型的输出。程序清单2给出了一个显示存储动态内存方式的示例。程序清单2将通常作为主外部循环的迭代了10次,并在每次迭代的末尾,调用函数mDisplay-Table()输出分配的内存块情况。

许多内存块均在初始化阶段进行分配,但我们对这些内存块并不感兴趣,因为这段代码将不会重复,因此不会产生内存。由于我们并不希望这些内存分配导致分配表混乱,因此在启动感兴趣的迭代之前需要将该分配表清空。为了清空分配表,需要调用函数mClearTable()。

主循环调用的三个不同的函数

函数replacer():指示了一个用来分配内存块并且直到出现循环迭代才释放的指针。如果检验主循环中的迭代,可以发现分配的内存块并未释放。通过监控总数为20的内存块,从表1可以看出,每次迭代之后的内存块总数都为1,因此没有出现内存

函数growAndShrink():管理长度为24个结构体的链表,该链表的长度将随时间发生变化,但我们并不希望链表无限增长。通过检验总数为24的内存块,我们可以发现,虽然任意时间内存块的数目都可能发生变化,但决不会超过25个。

函数growForever():处理内存块长度为44的情形。这里我们可以非常清晰地看到,分配的内存块数目在持续增长。当首次观察该表时,可能无法找到表的源头。我们首先只能快速而粗略对mMalloc()上的条件断点进行检验,该断点只有当长度参数达到44时才触发。当到达该断点时,可以检验堆栈,以确定进行内存分配的地方。工程师完全能够多次执行这样的操作,因为这种长度的内存块可在多处进行分配。

严格地说,在函数growForever()中分配的内存不是,因为所有分配的内存块均带有引用,因此理论上可以在后来释放。如果特定应用这样做,那么结果就非常明显。

长度是关键因素

当不同类型的对象共享相同长度的内存时,上述技术就不那么有效了。实际中碰到这样的情形并不多,但即便可能引发问题,仍然还有很多别的选择。

更为先进的方法则是为每个记录存储类型信息。这并不困难,但我却不愿采用这种方法,因为该方法要求为函数mMalloc()的标记添加一些新东西。我们可以定义一个列出所有可能分配的类型的枚举类型。在每次调用函数mMalloc()时,将传递一个附加的参数,并且该参数为枚举类型中的一个元素。如果在表中该参数连同地址一起被存储,那么总能识别出这类对象。

这也使得我们可以将分配长度不同,但类型相关(如可变长度的字符数组)的内存块链接起来。

C++通过使我们重载或删除按类基(per-class basis)而使得这种方法更加简便易行。尽管这是一种有效的方法,但这里我仍然不会采用这种方法,因为我更倾向采用适合C语言环境的技术。

linux操作系统文章专题:linux操作系统详解(linux不再难懂)

上一页 1 2 下一页

评论


相关推荐

技术专区

关闭