adi blackfin dsp处理器中的多堆(Multiple Heaps)技术

来源:互联网 发布:淘宝评价体系 编辑:程序博客网 时间:2024/04/30 18:23
 

Introduction

在嵌入式软件开发中,一般不建议使用动态内存分配。一个主要的原因就是嵌入式系统的资源十分有限,动态内存分配很容易导致系统运行异常。具体地讲,在blackfin dsp系统中,默认的堆空间在L1memory中,而L1空间是很有限的,如BF533处理器,其L1中的DATA空间只有64K。然而,不使用动态内存分配,使得代码有时看起来会比较奇怪,维护起来很不方便。本文介绍adi blackfindsp处理器提供的多堆技术,使用者除了使用系统默认的堆空间外,还可以自己建立堆空间,自由指定堆的大小和空间,动态内存从自己建立的堆空间中分配。

blackfin c/c++ 运行时库(run-time library)标准的堆管理函数:calloc, free, malloc,和relloc。系统运行时,默认只有一个堆。用户可以定义多个堆,这些扩展的堆管理函数为heap_calloc, heap_free,heap_malloc and heap_realloc。多堆技术使得用户可以在fast-but-scarcememory(即L1或L2)中定义堆,也可以在slower-but-plentiful memory (SDRAM)中定义堆。 定义堆 堆可以在链接时或运行时定义。不管是何种方式,都需要指定堆的三种特征:

  • 起始地址(最低可用的地址);
  • 长度(字节);
  • 标记(userid,>=1);

系统默认堆,在链接时指定,userid是0。另外,堆还有一个属性叫做索引(indices),indices与userid类似,不同之处在于它是系统定义的。在使用自定义堆时,必须使用indices而不是userid。用户可以调用函数_heap_lookup() 进行userid到indices的转换。 在链接时定义堆链接时定义的堆在heaptab.s文件中定义,堆的起始地址、长度和userid用32位字表示。各个堆定义在一个称之为“_heap_table”的表中。这个表必须首先包含默认堆(userid为0),必须以一个入口地址为0的项目结束。表中的地址可以是真实的地址值(如0×02000000),也可以使在ldf文件中定义的符号。默认堆必须使用ldf中定义的符号。 “_heap_table”表存在于constant存储空间中,当第一次对某个堆进行请求时,它被用来运行时初始化堆结构___heaps,并设置___nheaps作为可使用堆的编号。 注意:堆的数量是有上限的,即MAXHEAPS,在heapinfo.h中定义。目前这个值是4,即最多允许4个链接时堆。同样,这里指定的堆的编号要用_heap_lookup()函数得到系统辨识的indices,这个函数原型是: int _heap_lookup(int userid); // returns index

在运行时定义堆

可以用_heap_install() 函数在系统运行时定义堆: int _heap_install(void *base, size_t length, int userid); 这个函数可以使用任意一个存储块的地址作为堆的起始地址。它返回的是indices,也就是说不必再调用_heap_lookup()函数来进行转换。如果返回值小于0,则说明出错。出错原因可能是:

  • 在_heaps表中没有足够的空间;
  • 指定的userid已经存在;
  • 指定的堆太小了;

tips

  • 堆的起始地址不能是0×00000000,这个地址是为NULL指针保留的。
  • 堆中不是所有空间都可用来作内存分配用。有一部分是为housekeeping保留的。
  • 堆的起始地址必须是8字节对齐。
  • 堆的长度必须是2的整数次方,如256,512,1024字节。

标准堆操作接口

标准的堆操作函数,如malloc和relloc,总是在默认堆中分配内存。而space_unused 函数返回默认堆中剩余可用的空间大小。由于有内存碎片,可能不能分配所有可用的空间。

扩展的堆操作接口

C运行时库提供了扩展的堆接口函数,用于自定义的堆操作。这些函数是:heap_calloc, heap_free, heap_malloc, and heap_realloc。这些函数的用法和标准函数类似,只是需要指定操作的堆索引(index)。

  • void *_heap_calloc(int idx, size_t nelem, size_t elsize)
  • void *_heap_free(int idx, void *)
  • void *_heap_malloc(int idx, size_t length)
  • void *_heap_realloc(int idx, void *, size_t length)

heap_realloc(idx, NULL, length) 等效于 heap_malloc(idx, length) 。 而对于 heap_realloc(idx, ptr, length) 如果ptr != NULL, 则提供了idx参数将会被无视;reallocation总是在原来分配的堆上进行。 类似的 heap_free(idx, ptr) 也对idx参数无视。 heap_space_unused(int idx) 返回idx指定的堆空间的可用字节数。返回-1表示idx无效。 C++扩展接口 C++运行时库提供了new和delete的扩展接口。 C++中堆的定义和初始化和C描述的一样。这些堆还可以被new和delete使用。所需的操作仅仅是告诉new和delete要针对哪个堆进行操作。同样,不必要告诉delete操作的堆index。

例:

#include

char *alloc_string(int size, int heapID)

{

char *retVal = new(heapID) char[size];

return retVal;

}

void free_string(char *aString)

{

delete aString;

}

空间的释放

当堆中的空间被释放(free),这些空间并不返回给系统。而是由堆中的free list管理。如果需要,可以重新初始化堆(如内存碎片过多)。初始化堆的函数是:

int _heap_init(int index) 。

原创粉丝点击