malloc 的原理?malloc 的底层实现?

目录

1. malloc 的基本原理

2. malloc 的底层实现

a. 内存分配算法

b. 内存管理函数

c. 合并和分割

d. 内存碎片化处理

3. 常见的 malloc 实现库

4.示例


malloc 的底层实现是一个复杂的内存管理过程,它通过不同的算法和系统调用高效地管理动态内存分配和释放。在现代系统中,malloc 实现已进行了大量优化,以提高性能和减少内存碎片化。

malloc 是 C 语言中的一个动态内存分配函数,用于从堆中分配指定大小的内存块。它的底层实现涉及操作系统的内存管理机制和用户态的内存管理库(如 glibcmalloc 实现)。下面是 malloc 的基本原理和底层实现的简要介绍:

1. malloc 的基本原理

  • 功能malloc 用于动态分配内存。它接收一个参数,表示需要分配的字节数,并返回一个指向已分配内存块的指针。如果分配失败(例如内存不足),它返回 NULL
  • 内存来源malloc 分配的内存来自进程的堆区(heap),堆区是进程的可增长区域,位于程序的已使用内存区和未使用内存区之间。

2. malloc 的底层实现

  • malloc 的实现因库和操作系统不同而略有差异,以下是常见实现方式的主要步骤:

a. 内存分配算法

  • 自由链表(Free List):管理未分配的内存块,以加快分配速度。空闲块按大小排序,并形成链表。
  • 首次适配(First-Fit):寻找第一个足够大的空闲块用于分配。
  • 最佳适配(Best-Fit):寻找最接近所需大小的空闲块,以减少碎片化。
  • 快速适配(Fast-Fit):通过缓存特定大小的空闲块来加速内存分配和回收。

b. 内存管理函数

  • brksbrk:这些系统调用用于增加或减少进程的堆空间。brk 设置堆的结束地址,sbrk 调整当前堆的大小。
  • mmap:用于分配大块内存或当 brk 的调整不够用时直接映射内存,通常用于分配大于一定阈值的块。

c. 合并和分割

  • 分割:当找到的空闲块比请求的内存大时,会将块分割为两部分,一部分用于满足请求,剩余部分继续作为空闲块。
  • 合并:当内存被释放时,若相邻的块也是空闲的,它们会被合并以减少碎片化。

d. 内存碎片化处理

  • 内碎片:指分配的内存块比请求的稍大,导致小块内存被浪费。常通过合并和重新分配减少。
  • 外碎片:指小的空闲块分布在内存中,无法满足较大内存请求。通过内存紧缩(如 mremap)减少外碎片。

3. 常见的 malloc 实现库

  • glibcmalloc:广泛用于 Linux 系统的 C 库实现,采用分离适配器机制,支持快速分配、延迟合并等优化。
  • jemalloctcmalloc:高级的内存分配库,优化了多线程环境下的性能和减少内存碎片的能力。

4.示例

#include <stdio.h>
#include <stdlib.h>  // 包含 malloc、free 函数

int main() {
    // 请求分配 10 个 int 类型大小的内存块
    int *arr = (int *)malloc(10 * sizeof(int));
    
    // 检查分配是否成功
    if (arr == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // 使用分配的内存
    for (int i = 0; i < 10; i++) {
        arr[i] = i * i;
    }

    // 打印已分配内存中的数据
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放分配的内存
    free(arr);

    return 0;
}

分析该示例背后的 malloc 底层操作

  1. 请求内存:程序调用 malloc 请求 10 个 int 大小的连续内存块,总计 10 * sizeof(int) 字节(通常是 40 字节)。

  2. 内部操作

    • 寻找合适块malloc 从自由链表中查找一个合适的空闲块。如果找到足够大的块,它将返回该块的起始地址。
    • 分割:如果找到的空闲块大于请求的内存大小,malloc 可能会将该块分割成两部分:一部分用于满足请求,另一部分留作空闲。
    • 系统调用:如果堆上没有足够大的空闲块,malloc 可能会通过 brkmmap 向操作系统请求更多内存。
  3. 内存使用:程序在已分配的内存中写入数据,arr[i] = i * i;。分配的内存在使用后必须被释放,否则会导致内存泄漏。

  4. 释放内存

    • 调用 free(arr) 释放内存,free 会将内存块标记为可用,并尝试与相邻空闲块合并以减少碎片化。
    • 释放的内存不会立即返回给操作系统,而是保留在堆上供后续的 malloc 请求使用。

模拟底层操作的简单示例

为更直观地理解 malloc 的内部分配和释放,假设堆管理如下所示:

Heap Before Allocation:
-----------------------------------
| Free Block | Used Block | Free Block |
|    100B    |    50B     |   200B    |
-----------------------------------

After malloc(40B):
-----------------------------------
| Free Block | Used Block | Used Block | Free Block |
|    100B    |    50B     |    40B     |   160B    |
-----------------------------------

After free(40B):
-----------------------------------
| Free Block | Used Block | Free Block | Free Block |
|    100B    |    50B     |    40B     |   160B    |
-----------------------------------

After Coalescing:
-----------------------------------
| Free Block | Used Block | Free Block |
|   140B     |    50B     |   160B    |
-----------------------------------

这个例子展示了 malloc 的分配过程、内存块的管理和 free 后的合并操作,有助于理解 malloc 如何高效管理内存。

### Malloc 函数的底层实现机制 Malloc函数用于动态分配指定大小的内存块,返回指向该内存块起始位置的指针。当程序请求一定量的内存时,`malloc()`会尝试找到合适大小的未被使用的内存片段并将其标记为已占用。 对于较小尺寸(通常小于128KB)的内存请求,`malloc()`利用`brk()`系统调用来调整进程的数据段边界,从而扩展可用堆空间[^4]。具体来说,这涉及到移动_edata指针到更高的地址处,以便腾出更多可分配的空间[^2]。而对于较大尺寸(超过128KB)的需求,则更倾向于采用`mmap()`映射文件或设备到内存的方式获取新的页面,这种方式允许独立管理大块非连续存储区而不影响其他部分。 为了避免频繁地向操作系统发出额外的内存请求以及减少碎片化的影响,现代版本的glibc库中的`malloc()`实现了所谓的“内存池”,即预先保留一部分较大的连续区域作为内部缓冲区供后续的小规模分配使用[^1]。这种策略不仅提高了效率而且有助于优化整体性能表现。 当应用程序不再需要之前获得过的某片特定区域内存资源时,可以通过调用`free()`来通知运行时环境回收这部分空间。然而值得注意的是,并不是所有的释放动作都会立刻触发将这些空闲出来的字节交还给内核的行为;只有当整个页范围都处于闲置状态并且满足某些条件的情况下才会真正归还给OS。 #### 内存分配流程示意图 ```mermaid graph TD; A[开始] --> B{查找合适的空闲块}; B -- "存在" --> C[直接分配]; B -- "不存在" --> D{判断所需大小}; D -- "<= 128KB" --> E[通过brk增加堆空间]; D -- "> 128KB" --> F[通过mmap映射新页面]; G[结束] style A fill:#f96,stroke:#333,stroke-width:4px style B fill:#bbf,stroke:#000,stroke-width:4px style C fill:#bfb,stroke:#000,stroke-width:4px style D fill:#bbb,stroke:#000,stroke-width:4px style E fill:#ff7,stroke:#000,stroke-width:4px style F fill:#faa,stroke:#000,stroke-width:4px style G fill:#afa,stroke:#000,stroke-width:4px ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值