简体   繁体   English

动态内存分配器

[英]Dynamic Memory Allocator

Given the following question, with provided answers below:鉴于以下问题,并提供以下答案:

在此处输入图片说明

在此处输入图片说明

How can I compute the values in the green outlined areas?如何计算绿色轮廓区域中的值? I believe I have a pretty solid understanding on how the free() function in C, works and what it does: clears the memory block dynamically allocated on the heap stack (either removing it entirely, or making it free for use, to future allocates).我相信我对 C 中的free()函数如何工作以及它的作用有一个非常扎实的理解:清除堆堆栈上动态分配的内存块(要么完全删除它,要么让它免费使用,以备将来分配)。

What I don't understand is how a call to free(0x400b010) changes only some of the other heap blocks above?我不明白的是对free(0x400b010)的调用如何仅更改上面的其他一些堆块? (those I've outlined with green). (那些我用绿色勾勒出来的)。 I get that the address 0x400b010 (with binary value: 01000000 00001011 01100000 00011100 does not change, as per the assignment its already freed, having 0 in its bit 0 .我得到这个地址0x400b010 (二进制值: 01000000 00001011 01100000 00011100不改变,按照转让其已释放,其0在其bit 0

Can anyone explain this to me?任何人都可以向我解释这一点吗? For instance the block at address 0x400b00c:0x000000013 changes its value (second argument after :) to 0x00000022 , when the free is called upon the block above.例如,当在上面的块上调用 free 时,地址0x400b00c:0x000000013处的块将其值(: 之后的第二个参数)更改为0x00000022 This example is just one of the odd cases, where a block that is previously allocated ( 1 in bit 0 ) changes to be free, even though no free was called on that address.这个例子只是一种奇怪的情况,其中一个先前分配的块( bit 0 1 )变为空闲的,即使在该地址上没有调用空闲。

Similar some of the blocks change their values while others do not.类似的,一些块会改变它们的值,而另一些则不会。

I tried to engage this example in many different ways, and I have not been able to crack why the solution looks this way, so I hope someone in here can explain to me what exactly is going on.我试图以许多不同的方式参与这个例子,但我无法破解为什么解决方案看起来是这样,所以我希望这里有人可以向我解释到底发生了什么。

The pointers returned by malloc (and then later passed to free ) point at the first byte of the user content of the block, NOT at the header (or footer). malloc返回的指针(然后传递给free )指向块的用户内容的第一个字节,而不是页眉(或页脚)。 So to find the header of the block in free , you need to subtract 4 from the pointer argument (the size of the header).所以要在free找到块的头部,你需要从指针参数(头部的大小)中减去 4。

So when free(0x400b010) is called, the first thing is to subtract 4 and get the header of the block at 0x400b00c -- which is 0x13.因此,当调用free(0x400b010) ,首先要做的是减去 4 并在 0x400b00c 处获取块的标头 - 即 0x13。 This tells you that the block is 16 bytes (0x10) and is in use (bit 0 is set) and the previous block is in use (bit 1 is set).这告诉您该块是 16 字节 (0x10) 并且正在使用中(位 0 已设置)并且前一个块正在使用中(位 1 已设置)。 As part of freeing it, you need to check if either adjacent block is free.作为释放它的一部分,您需要检查相邻块是否空闲。 The bit 1 value tells you the previous block is not free, but to check the next block, you need to find it.位 1 值告诉您前一个块不是空闲的,但是要检查下一个块,您需要找到它。 To do that, you add the size (0x10) to the header address (0x400b00c) to get the next block's header address (0x400b01c), which igives you the header value of 0x12.为此,您将大小 (0x10) 添加到标头地址 (0x400b00c) 以获取下一个块的标头地址 (0x400b01c),它为您提供了 0x12 的标头值。 This block is free, so you add it's size to the current block and mark the current block as free by setting the header of the current block to 0x22 (so it is now a free 32-byte block).这个块是空闲的,所以你将它的大小添加到当前块,并通过将当前块的头设置为 0x22(所以它现在是一个空闲的 32 字节块)来标记当前块为空闲。 You now also need to find the footer of this new coalesced block (at header address + size - 8 == 0x400b024) and change that to 0x22 as well.您现在还需要找到这个新合并块的页脚(在标题地址 + 大小 - 8 == 0x400b024)并将其更改为 0x22。

It is not necessary to change the old footer of the block or the old header of the following free block that are being colasced, as these are now part of the contents of the free block (which are "don't care" values).没有必要更改块的旧页脚或下一个正在合并的空闲块的旧标题,因为这些现在是空闲块内容的一部分(它们是“无关”值)。 Nor is it necessary to touch the previous block, as it is (still) in use.也没有必要触摸前一个块,因为它(仍在)使用。

There's a few odd things about this setup.这个设置有一些奇怪的地方。

  • recording the free/in use state of the previous block in bit 1 is an unnecessary complication.在位 1 中记录前一个块的空闲/使用状态是不必要的复杂化。 You could check it just as well by looking at the footer of the previous block.您也可以通过查看前一个块的页脚来检查它。 If it was free, you'd need the previous block's footer value anyways to find its size (and header).如果它是免费的,那么无论如何你都需要前一个块的页脚值来找到它的大小(和标题)。
  • you really need to know the start and end of the heap in order to not accidentally go off the end checking the previous or next block.你真的需要知道堆的开始和结束,以免意外地结束检查前一个或下一个块。 If this was the last block on the heap, trying to get the header of the next block would lead to errors as you run of the end of the heap.如果这是堆上的最后一个块,则尝试获取下一个块的标头会导致在运行堆末尾时出错。

I tried to look for a figure, but couldn't find anything satisfactory.我试图寻找一个人影,但没有找到任何令人满意的东西。 I'll just try to explain with words.我只会试着用文字来解释。

If you compare the table on the left and right, you will see that the changed boxes are 0x400b00c, and 0x400b028, from 13 and 12 to 22 respectively.如果比较左右的表格,会看到变化的框分别是0x400b00c和0x400b028,分别从13和12变为22。

Note each memory block has a header and footer.请注意,每个内存块都有一个页眉和页脚。 Since free was carried out at 0x400b010, it indicates that 0x400b00c is the header.由于free是在 0x400b010 处执行的,因此表明 0x400b00c 是头。 Therefore, all the entries below( 400affc ~ 400b008) will be unchanged, since it will be unaffected by the free operation.因此,以下所有条目(400affc ~ 400b008)将保持不变,因为它不受自由操作的影响。

Looking up from 0x400b00c, there are previously 2 blocks:从0x400b00c往上看,之前有2个块:

  • block 1: 0x400b00c ~ 0x400b018区块 1:0x400b00c ~ 0x400b018
  • block 2: 0x400b01c ~ 0x400b028区块 2:0x400b01c ~ 0x400b028

Note that block 2 is not in use, since bit 0 indicates the use of current block , but the value 0x0000012 is even.请注意,块 2 未在使用中,因为bit 0 indicates the use of current block ,但值 0x0000012 是偶数。 Therefore, if block 1 is freed, block 1 and block 2 will be combined to form a new unused block altogether.因此,如果块 1 被释放,则块 1 和块 2 将组合在一起形成一个新的未使用块。

What happens here is that this merging process will be carried out as efficiently as possible.这里发生的是,这个合并过程将尽可能高效地执行。 Therefore, the previous footer of block 1 and the previous header of block 2 will be unchanged, since they don't need to.因此,块 1 的前一个页脚和块 2 的前一个页眉将保持不变,因为它们不需要。 Freeing memory spaces does not require initialization.释放内存空间不需要初始化。

Therefore, the only changes to be made are to the new header and footer of the new block , which is at positions 0x400b00c, and 0x400b028.因此,唯一需要更改的是新块新页眉和页脚,它们位于位置 0x400b00c 和 0x400b028。

Note there are 8 blocks between the new header and footer(inclusive), leading to 8 * 4 = 32 bytes.请注意,新的页眉和页脚(包括)之间有 8 个块,导致 8 * 4 = 32 个字节。 32 in binary is 100000, but since the previous block(unchanged block) is in use, bit 1 is set to 1 .二进制中的 32 是 100000,但由于前一个块(未更改的块)正在使用中,因此第 1 位设置为1 This results in 100010, which is in hexadecimal 22.结果是 100010,它是十六进制 22。

Sorry if this explanation is confusing, do ask if you can't understand any part of this answer.抱歉,如果此解释令人困惑,请询问您是否无法理解此答案的任何部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM