malloc申请的内存大小_malloc最大能申请多大的空间

malloc申请的内存大小_malloc最大能申请多大的空间内存管理第三讲笔记 malloc/free(一)前言malloc和 free 作为 c 语言中的内存申请函数(new是运算符),malloc 实际上依据申请的空间大小,大空间调用操作系统的 API(HeapAlloc()),小空间使用SBH(小于等于1K)

内存管理第三讲笔记 malloc/free(一)   前言   malloc和 free 作为 c 语言中的内存申请函数(new是运算符),malloc 实际上依据申请的空间大小,大空间调用操作系统的 API(HeapAlloc()),小空间使用SBH(小于等于1K)。   SBH 是 Small Block Heap 的缩写,进行操作系统之上的小区块内存的管理。在 VC6 中可找到源码实现,升级版本 VC10 中统一使用系统API进行内存申请, SBH 被整合到了操作系统内部。   malloc与free带来的内存管理是应付小区块的,即SBH(small block heap),这点也可以从源代码中看出:   VC10下不会做门槛检测,它总是会调用系统提供的HeapAlloc。这是因为操作系统提供的函数也有类似的功能了。   一、VC6和VC10的malloc比较   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   vc6的SBH,在vc10中被放到了heapalloc()中   注意: heap_init 和 ioinit 在 VC6 和 VC10 中都存在   二、vc6内存分配   我们分析的步骤是按照函数调用的次序来的:(从下往上的函数调用次序如下)
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   1、heap初始化( heap_init函数)   _heap_init(…) 、__sbh_heap_init() 说明 :   CRT 会先为自己创建一个 _ctrheap “独特”内存(HeapCreate), 然后从中配置 SBH 所需的 headers, regions(__sbh_heap_init).应用程序内存申请时如果 size > threshold 就以 HeapAlloc() 从 _crtheap 取.若size <= thread 就从 SBH 取(实际区块来自 VirtualAlloc())
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间1.操作系统内存管理的一些概念:可创建一块独特的空间并给其命名,之后相关操作所需的内存都取自这里【逻辑上分类】 1.1 HeapCreate 要求操作系统分配一块内存 1.2 _crtheap 全局指针变量,指向分配的内存空间,专为 CRT(C Run Time) 使用 CRT是C run-time library的简称,称为C运行时库 2.__ sbh_heap_init(),到 _ctrheap 指向的内存 16 * sizeof(Header) 空间 2.1 每个 SBH 中还有 16 个HEADER (当16 个HEADER用光后,会再进行分配)   header 结构分析   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   由HEADER数据结构知,其有两根指针,且有三个unsigned int型变量则其大小为4字节(即32bits),bitvCommit为上面那行的32bits,bitvEntryHi和bitvEntryLo则合起来为下面那行的64bits。在 _sbh_heap_init() 中含有对 Header 的配置,包括对所属的 region 的配置pHeadData 指向实际所管理的可分配的内存区块pRegin 指向管理 Region 区块,其中存储了所管理内存的控制信息   _ heap_init() 和 _ _ sbh_heap_init() 调用完成之后就可以进行下一步_ioinit(), 使用 SBH 对小区块的内存请求进行响应和分配了   2、计算真正区块大小   _ioinit()   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   进入该代码段,提出要求分配大小为256的空间即32 * 8【ioinfo的大小为6,对齐调整为8】,完成了应用程序启动后的“第一次”内存申请.   _malloc_dbg()   示例中按照 dbg 模式进行   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   _heap_alloc_dbg(nSize)   首先了解 SBH 对所分配的内存块的结构设计,可分为三部分: _ CrtMemBlockHeader、data[nDateSize]、anotherGap[nNoMansLandSize]。 由此可以知道当应用程序申请 data[nSize] 实际消耗的内存空间大小为 blockSize = sizeof(_CrtMemBlickHeader) + nSize + nNoMansLandSize;   由此又可知 _heap_alloc_dbg(nSize)的主要任务,调整申请的内存大小,增加DebugHeader,并进行值填充和初始化。
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   这里的nSize为传入参数即为前面要求分配的空间大小256byte【16进制下则为100h】,nNoMansLandSize宏定义大小为4。   而结构体_CrtMenBlockHeader (==这块是附加上去给debuger时用的东西==) 的大小如右上图所示:1.pBlockHeaderNext, 指向链表后内存块2.pBlockHeaderPre, 指向链表前内存块3.szFileName, 记录申请使用该内存空间所在的文件4.nLine, 记录申请使用该内存空间所在文件的行号5.nDataSize, 实际数据区的空间大小(应用程序实际使用到的内存块)6.nBlockUse, 表示当前内存块的类型, 如 _CRT_BLOCK、_NORMAL_BLOCK 等…7.IRequest, 操作流水号8.gap[nNoMansLandSize], 上下两处“栏杆”,保护应用程序实际使用到的内存,到发生内存越界的情况,调试器可以检查到
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   通过调用_heap_alloc_base来每个blockSize内存的头指针。 然后通过头尾指针将所有分配出来的block串接起来,变为一个链表.1.上图主要对分配的空间进行数据填充和值初始化,以后续对内存块管理2.在调试模式下,malloc 分配的内存都被管理在链表中(及时已被客户使用),因此调试器可以实现复杂的功能3._pFirstBlock、_pLastBlock 全局指针   _heap_alloc_base(size)   之前在通过heap_alloc_dbg中调用_heap_alloc_base来每个blockSize内存的头指针。现在来看看它具体步骤:   在知道所需要附加上的debuger的总的需求大小后【注意此时仍没有进行内存空间的分配,只是在发出需求】,进入_heap_alloc_base()进行判断.
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间1. 当应用程序进行内存申请时,内存相关底层实现会根据申请空间的大小选择不同的接口 1.1 当申请量小于等于 1016Bytes 时调用 sbh_alloc_block 1.2 当申请量大于 1016Bytes 时调用操作系统提供的API HeapAlloc() 从 crtheap(全局变量) 中取内存 2. __sbh_threshold = 1016 = 1024 – (2 * 4). 其中 2 * 4Bytes 对应两个 cookies 的开销   _sbh_alloc_block(…)   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   这里的操作是为前面传进来的经过debuger信息包装的数据再添加上头尾两个cookie,然后进行round up即调整到16的倍数关系【当添上头尾cookie后得到的大小不为16的倍数时,则round up成16的倍数大小】。   如这里的最终大小为0x130,所以cookie记录的信息是0x130。但这里为什么是0x131呢,因为这块内存是要分配出去的【而再最终分配内存都是16的倍数大小即十六进制的末位必为0】,所以通过采取末位bit为0或1的方式表示生成的这块内存到底是分配出去使用了【1】还是已被sbh回收未被使用【0】。   进行到这里,都还是在计算所需分配的内存的大小,仍没有真正地开始实际的分配内存的操作!!1.(应用程序实际申请量 + DebugHeader + cookie * 2) 向上调整 16 字节 【类似于 std::alooc 中的 ROUNDUP()】2.0×100 + 0x24 + 4 * 2 = 0x12C = 130; 因为是16的倍数,所以上下cookie最后四位都为0,借用最后 1 bit来标记当前内存是否空闲(1用户使用,0空闲)   3、分配和管理内存   __sbh_alloc_new_region()   接下来进入到 _sbh_alloc_new_region() 即开始进入实际分配内存前置操作 【需要构建一个region控制台,仍未开始实际分配内存】: region内部结构如图:   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   由上知,有16个HEADER,而HEADER中的两个指针如图,一个指向region,一个指向1MB的系统虚拟地址空间【调用_virtual_alloc】。
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   这里的struct tagRegion里面: indGroupUse表示了当前会提供内存的group编号,从0开始 cntRegionSize[64]用64个字节去对应当前group所将会展开链表,当对应链表挂载有内存时,将会变成1,即最上面的深灰阴影的那一行 bitvGroupHi和bitvGroupLo共同构成了一个的byteMap共64个byte(分为32组),将来用于对应每个group中所挂载的64条双向链表,当对应的位置挂载有可用内存时,会变成1.   bitvGroupHi, bitvGroupLo 对应 32 * (32 * 2) = 32 * 64bit 的空间,对应32个Group中的64个双向循环链表,记录其中每个链表是否已有空闲节点【内存是否可以使用】(1表示有,0表示无)grpHeadList就是32个group,每个group负责32KB   struct tagGroup里面:cntEntries表示当前链表中进行了分配或释放空间的次数【正数则代表分配操作,负数则代表释放回收操作,0则表示系统已经将分配的空间全部回收或没有任何空间被分配使用】.listHead对应64对指针,也就是形成了64条链表,用于挂载不同大小的内存块,间隔为16byte,最后一条链表将挂载所有大于等于1K的内存块.   struct tagListHead里面:   两个tagEntry类型的指针对象【即为上面Group表中的那64对指针】.   struct tagEntry里面:   sizeFront表示链表剩余内存的大小,为了节省内存 sizeFront 借用了上一个 Entry 的pEntryPrev。所以在GroupX中的64对某对链表指针没被投入使用时,一般都是往上指向前一个pEntryprev指针的地址从而向下包含3个的。如下图所示。   pEntryNext和pEntryPrev表示类似双向链表的指针
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   而上面region的这些东西的大小为4+64+64 * 4 +32 * (4 + 64 * 8) = 16836 byte, 而16836 / 1024 = 16.33KB,即需要创建一个region消耗16KB的空间去管理系统分配出来的1MB的空间。   __sbh_alloc_new_group()   开始进入实际分配内存操作.
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间一个 Header 对应管理 1MB 内存,其被逻辑分为 32 块(1MB / 32 = 32kB) 对应到 32 个 Group 每块内存又被分为 8 page(32KB / 8 = 4KB)每个 page 被组织到 Group 的最后一条链表中当有内存请求时,便从此链表中进行切割提供。当 Group0 再无内存可用,Group 1 便再去管理对应逻辑分块的第二块内存进行分配   Group中 listHead 管理规则:   listHead[0] 管理 16 字节内存块,依次叠加 16 字节增长至 listHead[63] (1024)。其中所有大于等于 1KB 的内存块都被 listHead[63] 管理
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   而对于每个page,其有两个防护cooike【0xffffffff】,防止填充或合并内容时出现越界而修改其结构出错。4096 – 2 * 4 = 4088,而填充的内容又必须调整为16的倍数,所以调整为4080byte,然后剩余的8byte作为无用的保留内容。   另外这有点像前面第二讲所说的,即先取出一大块内存空间,然后做切割再把它串接起来,然后挂在对应链表指针上。而在这里一开始是先实际分配了32KB的系统内存【==1MB只是相当于一个门牌号标识作用,实际只是产生分配了32KB去使用==】,然后是挂在Group0下的最后一对即[63]指针上的。一直等到将Group0上的32KB分配完了再出现从(1MB – 32KB)的系统内存空间再要一块32KB的然后归于Group1管控安排。   而且,这里虽然也像第二讲那样,将64对指针划分成各自负责的编号,即:   [0]对指针负责大小为16byte的内存;   [1]对指针负责大小为32byte的内存;   [2]对指针负责大小为48byte的内存;   ……   [63]对指针此时应负责大小为1024byte的内存【但实际由图知,[63]此时负责的是8*4096byte=32KB大小的内存】,且大于1KB即1024byte的都由最后这对指针负责,只有当切分到的内存空间小于1KB时才对应看应归属于前面的哪条链表【但此时也是有条件的,即使此时计算得出其归属于何种链表时,还应看此时该链表是否是可用状态。若可使用状态对应状态标识量为0(即那记录对应32组Groupx的各自64对指针的是否存在的64bits的那一长串链表),则会强行归属于[63]对指针管控分配而不属于计算所得应归属于对应[x]的指针管控!!】。上图黄色标注 0xffffffff (-1) 可理解为“阻隔器”,在内存回收合并时使用,保证相邻的page总是被分离的(不会交融合并)上图红色标注三个区块是 ENTRY 结构,4080 对应 sizeFont (表示空闲字节数), 是阻隔器之间空间大小已知 1page 是 4096 字节, 减去两个”阻隔器“ 4096 – (2 * 4) = 4088,预留(浪费)8字节以进行 16 对齐 4088 – 8 = 4080在上图 Group 结构中,只有 64 对指针,并没有看到 sizeFont。这因为 Group 只是自由链表的辅助节点,并未对应实际的page空间,因此为了节省内存 sizeFront 借用了上一个 Entry 的pEntryPrev   使用者ioinit申请分配空间时的切分空间操作:   
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   ioinit申请的时256byte的大小空间即小于1KB的【16进制下为100h,经过包装后12Ch向上调整为130h】且经计算应由[18]负责进行分配【130h/10h=13h ==->== 16+3-1=18】,但由于一开始[18]的状态标识量为0即该链表下的内存空间为空,所以一开始其是从[63]对指针负责的page1开始分配的。
malloc申请的内存大小_malloc最大能申请多大的空间
malloc申请的内存大小_malloc最大能申请多大的空间   4080在16进制下为ff0,此时需要分配130大小的空间出去,则还剩下ec0大小的内存空间,并将剩余的内存空间ec0挂回[63]那对指针负责下次分配。而此时,0x00000131这块地址已经返回给申请者ioinit使用所以0x00000130->0x00000131表示该内存空间已被分配使用。   函数调用栈返回,返回应用程序申请得到的内存地址ioint 进行了第一次 0x100 Bytes 的内存申请经过调整为 0x130 Bytes [(应用程序实际申请量 + DebugHeader + cookie * 2) 向上调整 16 字节对齐]调整 sizeFront 为 0xEC0 (0xFF0 – 0x130 = 0xECO)切割 0x130 大小内存,填充上下 Cookie 空间为 0x131 (130 – > 131 前面已解释)返回申请得到的内存空间(不包含 Cookie 地址)填充构造 DebugHeader 返回用用程序实际申请大小的内存空间 (不包含 DebugHeader)

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/62610.html

(0)
上一篇 2024年 8月 28日
下一篇 2024年 8月 28日

相关推荐

关注微信