malloc函数内存分配原理

news/2024/9/20 4:29:36/ 标签: 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.ppmy.cn/news/1527889.html

相关文章

jmeter 录制APP脚本

一、手机 1、修改网络 代理选择手动→填写服务器主机名&#xff08;电脑IP&#xff0c;如&#xff1a;192.1xx.x.xx&#xff09;→服务器端口&#xff08;任意未被占用端口&#xff0c;如&#xff1a;8888&#xff09; 2、安装证书 手机浏览器访问服务器主机名:服务器端口&a…

linux 解压缩

1、tar命令 # 压缩文件 file1 和目录 dir2 到 test.tar.gz tar -zcvf test.tar.gz file1 dir2 # 解压 test.tar.gz&#xff08;将 c 换成 x 即可&#xff09; tar -zxvf test.tar.gz # 列出压缩文件的内容 tar -ztvf test.tar.gz 释义&#xff1a;-z : 使用 gzip 来压缩和解压…

GPT对话知识库——串口通信的数据的组成?起始位是高电平还是低电平?如何用代码在 FreeRTOS 中实现串口通信吗?如何处理串口通信中的数据帧校验吗?

目录 1&#xff0c;问&#xff1a; 1&#xff0c;答&#xff1a; 串口数据的组成 串口数据传输帧的完整结构 起始位的电平状态&#xff1a;低电平 举例&#xff1a;UART数据传输的例子 适用场景 总结 2&#xff0c;问&#xff1a; 2&#xff0c;答&#xff1a; a. 如…

滚雪球学SpringCloud[4.2讲]: Zuul:Netflix API Gateway详解

全文目录&#xff1a; 前言4.2 Zuul&#xff1a;Netflix API GatewayZuul的基础配置与使用引入Zuul依赖启用Zuul配置路由规则 Zuul的过滤器机制编写自定义过滤器 与Spring Security的集成配置Spring Security结合Zuul过滤器进行认证 实例案例&#xff1a;使用Zuul保护微服务 预…

【软考】数据字典(DD)

目录 1. 说明2. 数据字典的内容2.1 说明2.2 数据流条目2.3 数据存储条目2.4 数据项条目2.5 基本加工条目 3. 数据词典管理4. 加工逻辑的描述4.1 说明4.2 结构化语言4.3 判定表4.3 判定树 5. 例题5.1 例题1 1. 说明 1.数据流图描述了系统的分解&#xff0c;但没有对图中各成分进…

七种d3dcompiler_47.dll缺失怎么修复的方法,教你轻松解决d3dcompiler_47.dll缺失!

d3dcompiler_47.dll是 DirectX 的一部分&#xff0c;用于编译 Direct3D 着色器。如果这个文件缺失或损坏&#xff0c;可能会导致某些游戏或应用程序无法正常运行。以下是七种修复d3dcompiler_47.dll缺失问题的方法&#xff0c;教你轻松解决d3dcompiler_47.dll缺失&#xff01; …

BARTBERT

BART和BERT都是基于Transformer架构的预训练语言模型。 模型架构&#xff1a; BERT (Bidirectional Encoder Representations from Transformers) 主要是一个编码器&#xff08;Encoder&#xff09;模型&#xff0c;它使用了Transformer的编码器部分来处理输入的文本&#xff0…

Kotlin cancel CoroutineScope.launch的任务后仍运行

Kotlin cancel CoroutineScope.launch的任务后仍运行 import kotlinx.coroutines.*fun main() {runBlocking {val coroutineScope CoroutineScope(Dispatchers.IO)val job coroutineScope.launch {var i 0while (i < Int.MAX_VALUE) {iprintln(i)}}// 2ms 取消协程delay(…

利士策分享,赚钱与体重:一场关于生活平衡的微妙探索

利士策分享&#xff0c;赚钱与体重&#xff1a;一场关于生活平衡的微妙探索 在当今社会&#xff0c;赚钱与体重&#xff0c;这两个看似风马牛不相及的概念&#xff0c; 却在无形中交织着人们的生活轨迹。 它们不仅仅是数字上的增减&#xff0c;更是个人选择、生活方式乃至心理…

docker容器中的内存占用高的问题分析

文章目录 问题描述原因分析分析1分析2验证猜想 结论和经验 问题描述 运维新增对某服务的监控后发现&#xff1a;内存不断上涨的现象。进一步确认&#xff0c;是因为有多个导出日志操作导致的内存上涨问题。 进一步的测试得出的结果是&#xff1a;容器刚启动是占用内存约为50M…

智能负载均衡:分布式缓存的高效能解决方案

在当今快速发展的互联网时代&#xff0c;分布式缓存成为了提升网站性能和用户体验的关键技术。本文将深入探讨负载均衡算法在分布式缓存中的应用&#xff0c;分析各种算法的优缺点&#xff0c;并提供选择最佳算法的指导。通过实际案例&#xff0c;我们将展示如何通过智能的负载…

用Kimi输出流程图

1.输入 我希望设计一个ERP系统&#xff0c;请帮我简单列一个流程图&#xff0c;用mermaid输出2.输出

MySQL高级功能-窗口函数

背景 最近遇到需求&#xff0c;需要对数据进行分组排序并获取每组数据的前三名。 一般涉及到分组&#xff0c;第一时间就是想到使用group by对数据进行分组&#xff0c;但这样分组&#xff0c;到最后其实只能获取到每组数据中的一条记录。 在需要获取每组里面的多条记录的时候…

【笔记】枚举

文章目录 枚举的概念枚举步骤例题&#xff1a;百鸡百钱方案1方案二方案三 例题 枚举的概念 枚举&#xff1a;逐个尝试所有可能的方案。 先把问题划分成一系列离散的状态&#xff0c;然后遍历这些状态来求解问题。 比如求3x5y10的正整数解有多少&#xff0c;把x∈[0&#xff…

傅里叶变换的基本性质和有关定理

一、傅里叶变换的基本性质 1.1 线性性质 若 则 其中:a,b是常数 函数线性组合的傅里叶变换等于歌函数傅里叶变换的相应组合。 1.2 对称性 若 则 关于傅里叶变换的对称性还有 虚、实、奇、偶函数的傅里叶变换性质: 1.3 迭次傅里叶变换 对f(x,y)连续两次做二维傅里叶变换…

【笔记篇】Davinci Configurator TcpIp模块

目录 1 简介1.1 架构概览2 功能描述2.1 特性2.2 TCP/IP协议栈2.2.1 IPv62.2.2 IPv42.3 初始化2.3 状态机2.4 主函数2.5 故障处理3 集成3.1 静态文件3.2 动态文件4 API描述5 配置5.1 Socket 拥有者配置5.1.1 `<Up>_CopyTxData` callback5.2 单播地址分配方法5.2.1 IPv4 单…

【GeekBand】C++设计模式笔记1_介绍

1. 课程目标 理解松耦合设计思想掌握面向对象设计原则掌握重构技法改善设计掌握GOF核心设计模式 2. 什么是设计模式 目标&#xff1a;复用&#xff0c;以不变应万变 3. GOF设计模式 4. 从面向对象谈起 5. 深入理解面向对象 向下&#xff1a;深入理解三大面向对象机制 封装&…

Gitlab学习(009 gitlab冲突提交)

尚硅谷2024最新Git企业实战教程&#xff0c;全方位学习git与gitlab 总时长 5:42:00 共40P 此文章包含第30p-第p34的内容 文章目录 冲突提交不同人修改不同文件不同人修改同文件的不同区域不同人修改同文件的相同区域 同时变更文件名和文件内容gitLab功能拓展code review代码复…

Vue3: setup语法糖

一. setup语法糖 在 Vue 3 中&#xff0c;setup 语法糖是一种简化组件内部状态和方法管理的特性。它允许你将组件的逻辑直接编写在组件的定义中&#xff0c;而不是像 Vue 2 那样需要在 methods 和 data 属性中管理。setup 语法糖基于 ES6 的类的静态方法&#xff0c;允许你更灵…

HttpMediaTypeNotAcceptableException: No acceptable representation问题解决方法

Background org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation HttpMediaTypeNotAcceptableException: No acceptable representation 异常通常发生在Web应用程序中&#xff0c;客户端请求了一个资源&#xff0c;但是…