POSIX 标准内存管理

更新时间:
2024-04-02
下载文档

POSIX 标准内存管理

POSIX 标准内存管理相关的函数在功能和内部行为上与“变长内存管理”节中讲的变长内存管理完全相同。POSIX 规定,通过 malloc、calloc 和 realloc 分配的内存地址必须对齐。规定地址对齐的目的是为了在任何硬件平台上高效地访问任意类型的数据结构,同时还可以避免在某些硬件平台上,因为在不对齐的地址上进行多字节访问造成的硬件异常错误。这一点也与 SylixOS 内部的默认处理一致。换句话说,SylixOS 内存管理本身就符合 POSIX 标准。每创建一个新的进程,系统内部会自动分配内存为其创建内存堆,而不是像内存区域那样需要用户指定内存空间。

分配内存

#include <malloc.h> 
void *malloc(size_t     stNBytes);
void *calloc(size_t     stNNum, size_t  stSize);
void *realloc(void     *pvPtr,  size_t  stNewSize);

函数 malloc 原型分析:

  • 此函数成功返回分配的内存指针,失败返回 LW_NULL 并设置错误号。
  • 参数 stNBytes 表示分配内存的字节数。

函数 calloc 原型分析:

  • 此函数成功返回分配的内存指针,失败返回 LW_NULL 并设置错误号。
  • 参数 stNNum 表示数据块的数量。
  • 参数 stSize 表示一个数据块的大小,以字节为单位。

注意
calloc 的参数似乎表明它分配的是 stNNum 个大小为 stSize 的内存,但实际上它分配的是一个大小为 stNNum stSize 的连续地址空间的内存,这点与 malloc 并没有差异。不同于 malloc 的是,calloc 会将分配的的内存进行清零处理。

函数 realloc 原型分析:

  • 此函数成功返回分配的内存指针,失败返回 LW_NULL 并设置错误号。
  • 参数 stNewSize 表示新分配内存的字节数。

注意
realloc 的行为与“变长内存管理”节中的 Lw_Region_Realloc 完全一致,这里不再赘述。

调用 malloc 函数可以为应用程序分配内存,在 SylixOS 中支持 3 中内存分配方法:dlmalloc 方法、orig 方法(这个方法由 SylixOS 内核实现,因此通常用在内核的内存分配中)、tlsf 方法。

dlmalloc 是一种内存分配器,由 Doug Lea 在 1987 年开发完成,被广泛应用在多种操作系统中。dlmalloc 采用两种方式申请内存,如果应用程序单次申请的内存量小于 256kb,dlmalloc 调用 brk 函数扩展进程堆空间,但是 dlmalloc 向内核申请的内存量大于应用程序申请的内存量,申请到内存后 dlmalloc 将内存分成两块,一块返回给应用程序,另一块作为空闲内存先保留起来,下次应用程序申请内存时 dlmalloc 就不需要再次向内核申请内存,从而加快了内存分配效率。当应用程序调用 free 函数释放内存时,如果内存块小于 256kb,dlmalloc 并不马上将内存块释放,而是将内存块标记为空闲状态。这么做的原因有两个:一是内存块不一定能马上释放回内核(比如内存块不是位于堆顶端),二是供应用程序下次申请内存使用(这是主要原因)。当 dlmalloc 函数中空闲内存量达到一定值时才将空闲内存释放回内核。如果应用程序申请的内存大于 256kb,dlmalloc 函数调用 mmap 函数向内核申请一块内存,返回给应用程序使用。如果应用程序释放的内存大于 256kb,dlmalloc 函数马上调用 munmap 函数释放内存。dlmalloc 不会缓存大于 256kb 的内存块。

tlsf 主要用于支持嵌入式实时系统的动态内存管理,它结合了分类搜索算法和位图搜索算法的优点,速度快、内存浪费少,tlsf 的 malloc、free 的时间复杂度并不随空闲内存块的数量而变化,总是 O(1)。

注意
tlsf 虽然拥有 O(1)时间复杂度的内存管理算法,适用于实时操作系统,但是在 32 位系统上仅能保持 4 字节对齐特性,在 64 位系统上仅能保持 8 字节对齐特性,不满足 POSIX 对 malloc 具有 2 * sizeof(size_t)对齐的要求,所以有些软件可能会出现严重错误,例如 Qt/JavaScript引擎,所以使用时需慎重!只有确认应用没有 2 * sizeof(size_t)对齐要求时,方可使用。

SylixOS 中可以通过配置宏 LW_CFG_VP_HEAP_ALGORITHM 来选择使用哪种内存分配方法,该宏可在头文件 <SylixOS/config/kernel/memory_cfg.h> 发现。

分配指定对齐值的内存

#include <malloc.h> 
void *memalign(size_t  stAlign, size_t  stNbytes);
int   posix_memalign(void **memptr, size_t  alignment, size_t size); 

函数 memalign 原型分析:

  • 此函数成功时返回分配的内存指针,失败时返回 LW_NULL 并设置错误号。
  • 参数 stAlign 为对齐值,必须为 2 的幂。
  • 参数 stNbytes 为需要分配的内存大小。

函数 posix_memalign 原型分析:

  • 此函数成功返回 ERROR_NONE,失败返回错误码。
  • 输出参数 memptr 保存分配的对齐内存的指针。
  • 参数 alignment 为对齐值,必须为 2 的幂,同时该值必须不小于 CPU 字长。
  • 参数 size 为需要分配的内存大小,以字节为单位。

posix_memalign 为 POSIX1003.1d 中定义的函数,该函数不同于 memalign,它需要对齐值不小于 CPU 字长,这和 SylixOS 中的 Lw_Region_AllocateAlign 函数的要求是一样的。注意当该函数分配内存失败时, memptr 的值是未定义的,因此应用程序不应该以 memptr 的值是否为 NULL 来判断内存是否分配成功。

释放内存

#include <malloc.h> 
void free(void *pvPtr);

函数 free 原型分析:

  • 参数 pvPtr 为需要释放的内存指针。

如果输入参数 pvPtr 等于 NULL,则 free 函数不会做任何工作。free 函数可以释放以上所有内存分配函数所分配的内存。

带有安全检测的内存分配函数

#include <malloc.h> 
void *xmalloc(size_t    stNBytes);
void *xcalloc(size_t    stNNum,     size_t  stSize);
void *xrealloc(void    *pvPtr,      size_t  stNewSize); 
void *xmemalign(size_t  stAlign,    size_t  stNbytes);

上面的函数与对应名称(没有 x 前缀)的内存分配函数的功能相同,只是在行为上存在不同。当分配内存失败时,这些函数内部会将错误信息输出到标准错误输出设备,即 stderr,同时还会调用 exit 函数结束当前进程,因此判断这些函数的返回值将没有任何意义。使用这些函数可以在某些时候给应用程序带来方便,例如当应用程序中存在未检测内存是否分配成功的错误代码而访问空指针导致程序崩溃,此种错误常常难以检测。使用这类函数可以为我们提供有用的信息。但这类函数由于已经固定了内存分配失败时的行为(结束当前进程),很多时候并不能满足需求。

注意,这一组函数在某些系统中可能存在一个 xfree 函数来释放对应的内存,SylixOS 使用 free 函数释放。

文档内容是否对您有所帮助?
有帮助
没帮助