Introduction
在嵌入式软件开发中,一般不建议使用动态内存分配。一个主要的原因就是嵌入式系统的资源十分有限,动态内存分配很容易导致系统运行异常。具体地讲,
在blackfin dsp系统中,默认的堆空间在L1
memory中,而L1空间是很有限的,如BF533处理器,其L1中的DATA空间只有64K。然而,不使用动态内存分配,使得代码有时看起来会比较奇
怪,维护起来很不方便。本文介绍adi blackfin
dsp处理器提供的多堆技术,使用者除了使用系统默认的堆空间外,还可以自己建立堆空间,自由指定堆的大小和空间,动态内存从自己建立的堆空间中分配。
blackfin c/c++ 运行时库(run-time library)标准的堆管理函数:calloc, free, malloc,
和relloc。系统运行时,默认只有一个堆。用户可以定义多个堆,这些扩展的堆管理函数为heap_calloc, heap_free,
heap_malloc and heap_realloc。多堆技术使得用户可以在fast-but-scarce
memory(即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) 。