内存

基本概念

内存管理是开发过程中必须要关注的重要过程,它包括内存的分配、使用和回收。

良好的内存管理对于提高软件性能和可靠性有着十分重要的意义。

使用场景

针对用户态开发,OpenHarmony内存提供了一套内存系统调用接口,支持内存的申请释放、重映射、内存属性的设置等,还有C库的标准内存操作函数。

功能

表 1 标准C库相关接口

头文件

接口

功能

strings.h

int bcmp(const void s1, const void s2, size_t n)

比较字节序列。

strings.h

void bcopy(const void src, void dest, size_t n)

拷贝字节序列。

strings.h

void bzero(void s, size_t n)

写入零值字节。

string.h

void memccpy(void dest, const void src, int c, size_t n)

拷贝src 所指的内存内容前n 个字节到dest 所指的地址上。复制时检查参数c 是否出现,若是则返回dest 中值为c 的下一个字节地址。

string.h

void memchr(const void s, int c, size_t n)

在s所指内存的前n个字节中查找c。

string.h

int memcmp(const void s1, const void s2, size_t n)

内存比较。

string.h

void memcpy(void dest, const void src, size_t n)

内存拷贝。

string.h

void memmem(const void haystack, size_t haystacklen, const void needle, size_t needlelen)

找到一个子串。

string.h

void memmove(void dest, const void src, size_t n)

内存移动。

string.h

void mempcpy(void dest, const void src, size_t n)

拷贝内存区域。

string.h

void memset(void s, int c, size_t n)

内存初始化。

stdlib.h

void malloc(size_t size)

申请内存。

stdlib.h

void calloc(size_t nmemb, size_t size)

申请内存并清零。

stdlib.h

void realloc(void ptr, size_t size)

重分配内存。

stdlib.h/malloc.

void valloc(size_t size)

分配以页对齐的内存。

stdlib.h

void free(void ptr)

释放内存。

malloc.h

size_t malloc_usable_size(void ptr)

获取从堆分配的内存块的大小。

unistd.h

int getpagesize(void)

获取页面大小。

unistd.h

void sbrk(intptr_t increment)

更改数据段大小。

差异接口详细说明:

  • mmap

    函数原型:

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

    函数功能:申请虚拟内存。

    参数说明:

    参数

    描述

    addr

    用来请求使用某个特定的虚拟内存地址。如果取NULL,结果地址就将自动分配(这是推荐的做法),否则会降低程序的可移植性,因为不同系统的可用地址范围不一样。

    length

    内存段的大小。

    prot

    用于设置内存段的访问权限,有如下权限:

    • PROT_READ:允许读该内存段。
    • PROT_WRITE:允许写该内存段。
    • PROT_EXEC:允许执行该内存段。
    • PROT_NONE:不能访问。

    flags

    控制程序对内存段的改变所造成的影响,有如下属性:

    • MAP_PRIVATE:内存段私有,对它的修改值仅对本进程有效。
    • MAP_SHARED:把对该内存段的修改保存到磁盘文件中。

    fd

    打开的文件描述符。

    offset

    用以改变经共享内存段访问的文件中数据的起始偏移值。

    内存 - 图1说明: mmap与Linux实现差异详见与Linux标准库的差异章节。

    返回值:

    • 成功返回:虚拟内存地址,这地址是页对齐。
    • 失败返回:(void *)-1。
  • munmap接口

    函数原型:

    int munmap(void *addr, size_t length);

    函数功能:释放虚拟内存。

    参数说明:

    参数

    描述

    addr

    虚拟内存起始位置。

    length

    内存段的大小。

    返回值:

    • 成功返回0。
    • 失败返回-1。
  • mprotect接口

    函数原型:

    int mprotect(void *addr, size_t length, int prot);

    函数功能:修改内存段的访问权限。

    参数说明:

    参数

    描述

    addr

    内存段起始地址,必须页对齐;访问权限异常,内核将直接抛异常,kill该进程,而不会产生SIGSEGV信号给当前进程。

    length

    内存段的大小。

    prot

    内存段的访问权限,有如下定义:

    • PROT_READ:允许读该内存段。
    • PROT_WRITE:允许写该内存段。
    • PROT_EXEC:允许执行该内存段。
    • PROT_NONE:不能访问。

    返回值:

    • 成功返回0。
    • 失败返回-1。
  • mremap接口

    函数原型:

    void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, void new_address);

    函数功能:重新映射虚拟内存地址。

    参数说明:

    参数

    描述

    old_address

    需要扩大(或缩小)的内存段的原始地址。注意old_address必须是页对齐。

    old_size

    内存段的原始大小。

    new_size

    新内存段的大小。

    flags

    如果没有足够的空间在当前位置展开映射,则返回失败

    • MREMAP_MAYMOVE:允许内核将映射重定位到新的虚拟地址。
    • MREMAP_FIXED:mremap()接受第五个参数,void *new_address,该参数指定映射地址必须页对齐;在new_address和new_size指定的地址范围内的所有先前映射都被解除映射。如果指定了MREMAP_FIXED,还必须指定MREMAP_MAYMOVE。

    返回值:

    • 成功返回:重新映射后的虚拟内存地址。
    • 失败返回:((void *)-1)。