malloc函数内存分配原理

news/2024/9/20 1:01:42 标签: c语言

malloc 是一个库函数,在<stdlib.h> 头文件中,是在程序的运行时库(Runtime Library)中实现的。这个函数主要用于在程序运行期间动态地分配内存。当在 C 语言程序中使用 malloc 时,实际上是在调用运行时库提供的一个函数,该函数会尝试从进程可用的内存池中分配一块大小适合的内存区域,并返回一个指向这块内存的指针。

malloc分配内存的原理:

1. 初始化

第一次调用 malloc 时,它会初始化一个内存池。这个内存池通常是通过向操作系统请求一块连续的内存区域来创建的。在 Unix-like 系统中,这通常通过 sbrk 系统调用来实现;而在 Windows 中,则可能通过 VirtualAlloc API 来实现。(如果分配的内存比较大,则可能会用mmap方式)

2. 内存池管理

malloc 维护一个内存池,内存池中包含已经分配出去的内存块以及空闲的内存块。通常,malloc 使用某种数据结构(如链表、二叉树或其他高效的数据结构)来跟踪这些内存块的状态(已分配/空闲)和大小。

3. 分配内存

当程序调用 malloc(size_t size) 请求分配内存时,malloc 需要在内存池中找到一个足够大的空闲块来满足请求。如果内存池中有足够的连续空闲空间,malloc 会从这个空闲块中分割出一块大小为 size 的内存,并返回一个指向这块内存的指针。

4. 内存对齐

malloc 会确保返回的内存地址是按照平台要求对齐的,比如在 x86 架构中,内存地址通常需要对齐到 8 字节或 16 字节边界,以优化内存访问性能。(不是所有平台都是这样)

5. 扩展内存池

如果内存池中的空闲块不足以满足新的请求,malloc 会尝试扩展内存池。这通常通过再次调用 sbrk 或 mmap 来实现,从操作系统获取更多的内存。新增的内存会被添加到内存池中,并可用于后续的内存分配请求。

6. 内存碎片处理

在多次分配和释放内存之后,内存池中可能会出现大量的小块空闲内存,这些小块之间不连续,导致内存碎片。malloc 可能会尝试合并相邻的小块空闲内存,使其成为一个较大的空闲块,从而减少内存碎片。

7. 释放内存

当程序不再需要某块内存时,应通过调用 free 函数来释放它。free 会将这块内存标记为空闲,并可能尝试与相邻的空闲块进行合并,以减少内存碎片。

8. 特殊情况处理

如果 malloc 发现无法从操作系统获取更多的内存来满足请求,它会返回 NULL,表示内存分配失败。

malloc分配的内存是虚拟内存还是物理内存?

malloc 分配的内存通常是虚拟内存。这是因为现代操作系统使用了虚拟内存机制,将进程的地址空间与实际物理内存区分开来。

既然是虚拟内存,那么分配的虚拟内存会和物理内存进行映射吗?

malloc 分配内存后,并不会立即为新分配的内存区域映射物理内存。相反,操作系统通常采用一种叫做“延迟分配”或“按需分页”(demand paging)的技术。这意味着在新分配的内存块中,只有当程序试图访问其中的数据时,才会触发一个分页错误(page fault),此时操作系统才会实际分配物理内存给这个虚拟地址,并建立虚拟地址到物理地址的映射。

这种策略有几个好处:

1.节省资源:如果分配的内存没有立即使用,那么就没有必要浪费物理内存。

2.提高效率:只有当内存真正被使用时才分配,可以避免不必要的内存分配和管理开销。

3.内存复用:操作系统可以复用未被实际使用的虚拟内存地址空间,直到它们被访问为止。

所以,malloc 分配的内存块在初始状态下一般是未映射到任何物理内存的。只有当程序开始读取或写入这部分内存时,操作系统才会分配物理内存并完成映射。这种机制使得内存管理更加灵活和高效。


http://www.niftyadmin.cn/n/5666414.html

相关文章

公益入理塘,爱尔眼科“专科联盟”挂牌

2024年9月11日&#xff0c;成都爱尔眼科医院、理塘县藏医院“眼科专科联盟”揭牌仪式在理塘县藏医院隆重举行&#xff01; 由爱尔眼科四川省区医疗总监刘德根、成都爱尔眼科医院副院长巫雷带队&#xff0c;白内障科副主任王文惠、手术室护士杨梅、手术室护士肖婷、健教部唐青颖…

虚拟机共享文件夹开启后mnt/hgfs/下无sharefiles? --已解决

问题: linux虚拟机中的共享文件夹&#xff08;Share Folders&#xff09;没有自动挂载到 /mnt/hgfs 目录下 解决&#xff1a; 直接打开命令行&#xff08;任何位置&#xff09;&#xff0c;输入下命令即可&#xff1a; sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o…

秋招八股总结

transformer 损失函数 交叉熵的原理 公式 xi是true_label&#xff0c;yi是神经网络预测为正确的概率 对比学习loss 对比学习损失函数 InfoNEC Loss&#xff08;bge中也用的这个&#xff09; SimCSE的主要思想&#xff1a;同一句话通过不同的drop out作为正例&#xff0…

Maya动画基础

Maya动画基础教程&#xff08;完整&#xff09;_哔哩哔哩_bilibili 第一集 动画基础设置 altv播放动画 选择撕下副本 右键---播放预览 第二集 k帧记录物体的空间信息 初始位置清零 删除历史记录 s键key帧 自动记录位置信息 删除帧&#xff0c;按住右键选择delete 按shif…

yolov8多任务模型-目标检测+车道线检测+可行驶区域检测-yolo多检测头代码+教程

你只需看一次&#xff1a;实时且通用的多任务模型 A-YOLOM 插图 贡献 轻量化集成模型&#xff1a;我们开发了一种轻量级模型&#xff0c;能够将三个任务整合到一个统一的模型中。这对于需要实时处理的多任务场景尤其有利。自适应连接模块&#xff1a;特别为分割架构的颈部区域…

Three.js学习笔记

Three.js是一款基于原生WebGL封装的Web 3D库,向外提供了许多的接口。 它可以运用在在小游戏、产品展示、物联网、数字孪生、智慧城市园区、机械、建筑、全景看房、GIS等各个领域。 npm install three https://threejs.org/docs/index.html#manual/en/introduction/Installatio…

DPDK 简易应用开发之路 2:UDP数据包发送及实现

本机环境为 Ubuntu20.04 &#xff0c;dpdk-stable-20.11.10 发送数据包的通用步骤 初始化DPDK环境&#xff1a; 调用 rte_eal_init() 来初始化DPDK的EAL&#xff08;环境抽象层&#xff09;&#xff0c;这是所有DPDK应用程序的第一步&#xff0c;用于初始化硬件、内存和逻辑核…

TCP socket

TCP的socket和UDP大同小异&#xff0c;基本的代码结构都是相同的。一些相同的接口本文就不赘述了&#xff0c;例如&#xff0c;socket,bind&#xff0c;有需要看这篇文章UDP socket 服务端server 两步&#xff1a;初始化服务端&#xff0c;运行服务端 初始化服务端 创建soc…