malloc和free实现分析
函数原型
#include <stdlib.h>
/*
* 分配一块指定大小的、未初始化的连续内存
* sz: 想要分配的字节数
* 返回值:
* 成功时,返回指向新分配内存块的首地址
* 失败时,返回NULL
*/
void *malloc (size_t sz);
/*
* 分配指定数量个,长度为指定大小的、清零的连续内存
* num: 想要分配的元素数量
* sz: 每个元素的大小(以字节为单位)
* 返回值:
* 成功时,返回指向新分配内存块的首地址
* 失败时,返回NULL
*/
void *calloc (size_t num, size_t sz)
/*
* 调整先前由malloc、calloc或realloc分配的内存块的大小
* ptr: 指向先前分配的内存块的指针。如果ptr为NULL,realloc的行为与malloc相同
* sz: 新的内存块大小(以字节为单位)
* 返回值:
* 成功时,返回指向新分配内存块的首地址,新的内存块上会保留原始内存中的值,但是新增加的部分是未初始化的(可能会原地调整,首地址不变)
* 失败时,返回NULL,并且原始内存块没有被释放
*/
void *realloc (void *ptr, size_t sz)
// 释放由malloc、calloc或realloc分配的内存
void free (void *ptr)
linux地址空间
Linux进程地址空间是指每个进程在运行时所能看到的虚拟内存空间。它是一个抽象概念。
这个虚拟地址空间不是实际的物理内存,而是由操作系统和硬件(MMU, 内存管理单元)共同管理的一种映射。
进程看到的地址是虚拟地址,当它需要访问某个地址时,操作系统会将其翻译成实际的物理地址。
高地址
+---------------------------+
| |
| Kernel Space |
| |
+---------------------------+
| |
| Stack ↓ |
| |
+---------------------------+
| |
| Memory Mapping Segment ↓ |
| |
+---------------------------+
| |
| Heap ↑ |
| |
+---------------------------+
| |
| BSS Segment |
| |
+---------------------------+
| |
| Data Segment |
| |
+---------------------------+
| |
| Text Segment |
| |
+---------------------------+
低地址
一个典型的Linux进程地址空间从高到低通常包含以下几个区域:
- 内核空间:运行操作系统内核的代码。所有进程共享这部分空间,但用户程序无法直接访问。
- 用户空间:每个进程独享这部分空间。
- 栈: 存放局部变量、函数参数和函数返回地址。栈从高地址向低地址增长。
- 内存映射段: 用于动态加载共享库(如 libc.so)和通过mmap()映射的文件。
- 堆: 用于动态内存分配,比如使用malloc()或 new 分配的内存。堆从低地址向高地址增长。
- BSS段: 存放未初始化的全局变量和静态变量。在程序加载时,这部分内存会被自动清零。
- 数据段: 存放已初始化的全局变量和静态变量。
- 代码段: 存放程序的可执行代码以及常量数据。这部分内存通常是只读的,以防止代码被意外修改。
内核空间 (Kernel Space):
malloc原理
ptmalloc是glibc中的malloc实现。