Linux内存分配

以下内容引述《Linux/Unix系统编程手册》

堆上分配内存

进程可以增加堆的大小来分配内存,所谓堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减。通常将堆的当前内存边界称为"program break"

调整program break

改变堆的大小,就像命令内核改变进程的program break位置一样。最初,program break正好位于未初始化数据段末尾之后。
在程序加载program break位置之后,内核会在进程试图访问这些虚拟内存地址时自动分配新的物理内存页。
使用brk函数和sbrk函数可以调整program break到指定的位置。

#include 
int brk(void *end_data_segment);
void *sbrk(intptr_t increment);

当程序试图访问的数据位于初始化或者未初始化数据段中当前上不存在的部分时,就会引发分段内存访问错误(segmentation fault)(SIGSEGV信号)

堆上分配内存

一般情况下,C程序使用malloc函数在对上分配内存,用free函数释放内存。
比brk函数和sbrk函数的优势在于:

  • 属于C语言标准的一部分;
  • 更易于在多线程程序中使用;
  • 接口简单,允许分配小内存;
  • 允许随意释放内存块,这些内存块被维护于一张空闲内存列表中。

malloc和free的实现

malloc的实现很简单,首先扫描之前由free所释放的内存块列表,找到要求大于或等于要求的一块内存。等于则返回,大于则切割后返回正当的大小。
如果没有足够大的空间,那么malloc会调用sbrk函数分配更多的内存。
free将内存块置于空闲列表上,malloc会在分配时记录内存大小的整数值,内存块置于空闲内存列表(双向列表)中,free()会使用内存块本身的空间来存放链表指针,将自身添加到列表中。
随着对内存不断地释放和重新分配,空闲列表中的空闲内存会和已分配的在用内存混杂在一起。

malloc调试工具和库

使用glibc提供的malloc调试工具或者任何一款malloc调试库,都会显著降低发现这些缺陷的难度。
介绍下glibc提供的malloc调试工具的部分功能:

  • mtrace() 和 muntrace() 函数分别在程序中打开和关闭对内存分配调用进行跟踪的功能。这些函数配合MALLOC_TRACE搭配使用,该变量定义了写入跟踪信息的文件名。
  • mcheck() 和 mprobe() 函数允许程序对已分配内存块进行一致性检查。
  • MALLOC_CHECK_ 环境变量提供了类似于mcheck() 和 mprobe() 函数的功能。

堆上分配内存的其他方法

calloc和realloc

#include 
void *calloc(size_t numitems, size_t size);
void *realloc(void* ptr, size_t size);

函数calloc中,参数numitems指定分配对象的数量,size指定每个对象的大小,返回首地址。calloc会将内存初始化为0。
realloc函数用来调整一块内存的大小,而此快内存应是之前由malloc包中函数所分配的。参数ptr指定需要分配的内存地址,size为调整后的大小。
两个函数都需要使用free释放申请的内存块。
由于realloc可能会移动内存块,任何指向该内存块内部的指针在调用realloc之后都可能不再可用。仅有一种内存块的位置引用方法依然有效,即以指向此块内存起始处的指针再叫上一个偏移量来进行定位。

memalign和posix_memalign

设计函数memalign和posix_memalign的目的在于分配内存时,其实地址要与2的整数次幂对齐。

#include 
void *memalign(size_t boundary, size_t size);

#include 
int posix_memalign(void **memptr, size_t alignment, size_t size);

函数memalign分配size个字节的内存,其实地址是参数boundary的整数倍,而boundary必须是2的整数次幂。函数返回分配内存的地址。
而posix_memalign函数分配sizeof(void*)与2的整数次幂两者间的乘积。
在UNIX实现中,无法通过调用free来释放由memalign分配的内存。

在堆栈上分配内存

alloca通过增加栈帧的大小从堆栈上动态分配内存

#include 
void *alloca(size_t size);

使用alloca分配内存对比malloc有一定优势:

  1. 分配速度比malloc快;
  2. alloc不需要维护空闲内存块列表
  3. alloc分配的内存随栈帧的移除而自动释放

针对longjmp和siglongjmp以执行非局部跳转时,alloca比malloc容易避免内存泄漏,因为堆栈是由调用展开的,分配的内存会被自动释放。

你可能感兴趣的:(Linux系统编程,c++,linux)