2026/3/24 17:36:16
网站建设
项目流程
平面设计的网站有哪些网站,没网站可以做百度推广吗,网络营销论文4000字,wordpress 电影模版文章目录说明动态内存分配#xff08;重点#xff09;虚拟内存结构分配器功能malloc和free函数内存分配约束内存碎片空闲块的跟踪和释放跟踪空闲块方法隐式空闲链表隐式链表数据结构隐式链表#xff1a;查找空闲块隐式链表#xff1a;在空闲块中分配隐式链表#xff1a;释…文章目录说明动态内存分配重点虚拟内存结构分配器功能malloc和free函数内存分配约束内存碎片空闲块的跟踪和释放跟踪空闲块方法隐式空闲链表隐式链表数据结构隐式链表查找空闲块隐式链表在空闲块中分配隐式链表释放和合并隐式链表双向合并显式空闲链表显式链表中的插入操作LIFO 释放策略案例统一数据结构支持多种策略指针测试说明庄老师的课堂如春风拂面启迪心智。然学生愚钝于课上未能尽领其妙心中常怀惭愧。幸有课件为引得以于课后静心求索。勤能补拙笨鸟先飞一番沉浸钻研方窥见知识殿堂之幽深与壮美竟觉趣味盎然。今将此间心得与笔记整理成篇公之于众权作抛砖引玉。诚盼诸位学友不吝赐教一同切磋琢磨于学海中结伴同行。资料地址computing-system-security动态内存分配重点程序员使用动态内存分配器如 malloc在运行时获取虚拟内存VM。动态内存分配器管理进程虚拟内存VM中称为堆的一个区域。虚拟内存结构堆位于用户空间中运行时可扩展区域栈向下增长堆向上增长由brk指针标识堆用于运行时动态分配内存如malloc分配器管理堆区作为进程虚拟内存的一部分分配器功能分配器管理堆为可变大小的块集合。块的状态为已分配或空闲分配器的类型为显式分配器应用程序显式调用分配与释放如C语言中的malloc/free。意外分配器仅分配不释放依赖垃圾回收如Java中的new/GC。malloc和free函数malloc函数原型void *malloc(size_t size)成功时返回至少size字节的内存块指针若size为0行为未定义通常返回NULL失败时返回NULL并设置errno为ENOMEM。对齐要求在x86-64上对齐到16字节边界。free函数原型void free(void *p)将指针p指向的内存块归还给可用池p必须来自之前的malloc/calloc/realloc调用。多次释放同一指针会导致未定义行为。#includestdio.h#includestdlib.hvoidfoo(longn){longi,*p;/*Allocate a block of n longs*/// malloc返回的指针对齐到双字16字节p(long*)malloc(n*sizeof(long));if(pNULL){perror(malloc);exit(0);}/*Initialize allocated block*/for(i0;in;i)p[i]i;/*Do something with p*/.../*Return allocated block to the heap*/free(p);}可视化规则每个字节1B用方块表示分配需满足双字对齐要求。我将从程序员笔记的角度为您整理并翻译这份关于内存分配约束的内容内存分配约束应用程序约束内存请求灵活性应用程序可以发出任意顺序的malloc和free请求内存释放规则free请求必须针对已通过malloc分配的内存块显式分配器约束无控制权无法控制分配块的数量或大小。即时响应必须立即响应malloc请求不能重新排序或缓冲请求。内存来源必须从空闲内存中分配块只能将分配的块放置在空闲内存中。对齐要求必须对齐块以满足所有对齐要求64位系统上需要16字节(x86-64)对齐。内存操作限制只能操作和修改空闲内存。分配后限制一旦块被malloc分配就不能移动。内存碎片内存碎片分为内部碎片Internal Fragmentation和外部碎片External Fragmentation。内部碎片当块的有效负载小于其总大小。主要来源为对数据结构维护开销、对齐所需的填充字节、显示策略决策。外部碎片虽然总空闲内存足够但无单一空闲块能满足新请求。空闲块的跟踪和释放核心挑战如何仅凭指针确定释放多少内存如何跟踪空闲块分配小结构到大空闲块时如何处理多余空间多个合适块中如何选择如何复用已释放的块?确定释放内存的大小在块起始前保留一个“头部”字段存储快的总大小包含头部本身[header field]每个已分配块需额外一个字存储头部释放时通过指针反推头部获取大小。跟踪空闲块方法方法1隐式链表基于长度所有块无论空闲与否按地址顺序链接每个块需标记“已分配/空闲”通过遍历查找可用块。方法2显式链表仅在空闲块之间建立指针链接需在空闲块内预留指针空间方法3分离空闲链表按大小分类维护多个独立空闲链表提高查找效率方法4按大小排序的块使用平衡树如红黑树以块大小为键支持快速查找匹配块隐式空闲链表问题计算机内存需要管理很多小块空间每个小块称为块需要记录块的大小分配状态。如果用两个完整的字word计算机存储单位来存这两个信息会浪费空间解决方案当内存块按特定规则对齐时地址的最低位永远是0不再浪费一个完整的字来存分配状态而是把那个永远为0的最低位复用作为分配标志位。a1已分配的块a0空闲的块读取时的处理读取块大小时需要屏蔽那个被复用的最低位得到真实的块大小。-----------------|Size|a|←1个字-----------------|Payload|← 应用数据仅分配的块有-----------------|Optional|← 可选填充|padding|-----------------起始标记heap_start结束标记heap_end。块表示大小字/分配位示例布局16/016字空闲块32/132字已分配块64/064字空闲块8/1结束块已分配隐式链表数据结构隐式链表数据结构隐式链表头部访问隐式链表遍历链表隐式链表查找空闲块首次适配First Fit从堆起始位置开始搜索选择第一个满足需求大小的空闲块。时间复杂度为线性时间可能在列表前端产生碎片“splinters”。下次适配Next Fit类似首次适配但从上一次搜索结束的位置开始继续搜索。避免重复扫描无用块通常比首次适配快但可能导致更严重的碎片化。最佳适配Best Fit搜索整个列表选择剩余空间最少但仍能满足需求的空闲块。减少大块浪费提高内存利用率但运行速度通常慢于首次适配。属贪心算法不保证全局最优。隐式链表在空闲块中分配分割块Splitting当请求的空间小于空闲块时将块分割成已分配部分和新的空闲部分。示例split_block(p, 32)将64字节块分为32字节已分配块和32字节空闲块。隐式链表释放和合并简单释放仅清除分配标志位会导致“伪碎片”问题。即使有足够连续空闲空间也可能因未合并相邻空闲块而无法满足分配请求。隐式链表合并若被释放块前后有空闲块将其合并即可隐式链表双向合并边界标签技术Boundary Tags在空闲块末尾添加“边界标签”即尾部 footer复制头部信息。支持反向遍历实现与前一块的合并。增加存储开销但为通用且重要技术。块格式包含头部和尾部均含大小和分配位。四种合并情况情况1前后均为已分配当前释放块独立成为空闲块。情况2前块空闲后块已分配与前一块合并。情况3前块已分配后块空闲与后一块合并。情况4前后均空闲三块全部合并为一大块。显式空闲链表数据结构设计仅维护空闲块列表非全部块利用空闲块的 payload 区域存储链表指针需要前向next和后向prev指针因为下一个空闲块可能在任意位置仍需边界标签以支持合并相邻块空闲块格式大小字段 | a 标志 | next 指针 | prev 指针 | payload 和填充可选字段a 表示是否已分配逻辑上A ← → B ← → C 双向链表 A ←→ B ←→ C双向链表A←→B←→C双向链表物理上块可在内存中任意顺序排列前向链接连接下一个空闲块后向链接连接上一个空闲块。示例块大小32, 48, 32, 32, 48, 32, 32。显式链表中的分配操作分配前状态若干空闲和已分配块。执行malloc(...)请求内存若找到合适块则进行分割更新链表结构并返回指针。分配后状态新块被标记为已分配剩余部分保留在空闲链表中显式链表中的插入操作无序插入LIFO后进先出策略将释放的块插入空闲链表头部。优点实现简单时间复杂度为常数缺点研究表明碎片化程度高于地址有序FIFO先进先出策略将释放的块插入空闲链表尾部。优点同样简单快速缺点碎片化表现不如地址有序地址有序策略按地址顺序插入保持链表中块按地址升序排列a d d r ( p r e v ) a d d r ( c u r r ) a d d r ( n e x t ) addr(prev) addr(curr) addr(next)addr(prev)addr(curr)addr(next)。缺点需要遍历搜索插入位置优点研究显示其碎片化程度低于 LIFO/FIFO。LIFO 释放策略案例案例一普通释放释放前目标块前后均为已分配块操作将该块插入链表根部头部结果链表头更新为新释放的块案例二与后继块合并释放前目标块后接一个空闲块操作移除后继空闲块合并两个块将合并后的块插入链表头部结果减少碎片提升可用大块数量案例三与前驱块合并释放前目标块前接一个空闲块操作移除前驱空闲块合并两个块将合并后的块插入链表头部。结果形成更大的连续空闲区域案例四三重合并释放前目标块前后均为空闲块操作移除前后两个相邻空闲块三块合并成一个大块插入链表头部。结果显著降低外部碎片统一数据结构支持多种策略使用循环双链表结构单一数据结构支持多种策略组合首次适配First-fit vs 下一次适配Next-fit固定游标或随搜索移动。LIFO vs. FIFO插入为下一个节点LIFO。插入为前一个节点FIFO。指针测试