malloc中 heap block 的 blocksize 大小问题

heap block 引发的思考

问题背景:


Implicit Free Lists


                  Any practical allocator needs some data structure that allows it to distinguish block boundaries and to distinguish between allocated and free blocks. Most allocators embed this information in the blocks themselves. One simple approach is shown in Figure 9.35.





malloc函数第一次申请出的是payload区域顶端的内存区域,返回的指针指向该处。


在payload之前还有一个header的区域,这个区域记录了block size,这里作者有点误导,由于是8byte align

于是在只有最底位(图中的a,用来记录block是否已经allocated还是free)


 首先要理解malloc中block size的原理


这个问题要能搞定,填对,不然下面的demo看了没用。。。

这是在32bit的机器上

对于上面那个题目的题解:

                  This problem touches on some core ideas such as alignment requirements, minimum block sizes, and header encodings. The general approach for determining the block size is to round the sum of the requested payload and the header size to the nearest multiple of the alignment requirement (in this case 8 bytes). For
example, the block size for the malloc(1) request is 4 + 1 = 5 rounded up to 8. The block size for the malloc(13)request is 13 + 4 = 17 rounded up to 24.

Request        Block size (decimal bytes) Block header (hex)
malloc(1)                   8                                          0x9
malloc(5)                  16                                         0x11
malloc(12)                16                                         0x11
malloc(13)                24                                         0x19




64bit的机器的malloc采用的是16byte对齐的!


在linux 64bit的 Ubuntu上做测试:

 




malloc(42)

这里申请 42byte的空间,malloc返回的连续内存空间是 64byte的


42 byte,由于开始有8byte的block size 区域,

42+8 = 50;

由于16byte对齐,于是对齐到64byte


至于最后的temp == 65 ,那是因为最后一位是用来提示该内存区域是否allocated。由于该bit 位等于1,于是,是allocated



上述测试代码:

 

/***********************************************************
code writer : EOF
code date : 2014.07.27
e-mail:jasonleaster@gmail.com

code purpose:
	Find out what beyond the payload location. :)

************************************************************/
#include <stdio.h>
#include <stdlib.h>

#define MACHINE_ADDRESS_LENGTH 64

void print_dec2bin(int dec_number)
//Just a simple function which translate decimal number into binary numebr
{
	int temp = 0;
	
	int to_be_print = 0;
	
	int array[MACHINE_ADDRESS_LENGTH];
	
	for(temp = 0;temp <  MACHINE_ADDRESS_LENGTH; temp++)
	{
		array[MACHINE_ADDRESS_LENGTH-temp-1] = dec_number%2;
		dec_number >>=1;
	}	

	for(temp = 0;temp <  MACHINE_ADDRESS_LENGTH; temp++)
	{
		printf("%d",array[temp]);
	}	

	printf("\n");
}

int main()
{
	int *ptr = NULL;
	
	int temp = 42;//how many bytes to be allocated

	printf("byte to be allocated, temp : %d\n",temp);

	ptr = (int *)malloc(temp);

	if(ptr == NULL)
	{
		printf("malloc failed\n");
		return 0;
	}
	else
	{
		*ptr = 2014;//just write some data into payload location.
	}

	temp = *(ptr - 2);//You may never forget that this code must be run on 64-bits machine, and ptr point to 'int'!!!Attention!!
			// otherwise you have to change 'ptr-2' into 'ptr-1'
	
	print_dec2bin(temp);
	
	printf("temp : %d\n",temp);

	free(ptr);
	return 0;
}


再三提示那个ptr-2!



如果多次malloc,除了最后一个block之外,每个block前后都有记录block的block size段,最后一个只有header blocksize






ubuntu2@ubuntu:~$ ./a.out
ptr_void:0x185f010
foo_void:0x185f030
ptr_void header size:32
ptr_void foot   size:32
foo_void header size:32
foo_void foot   size:135104

最后的size是不是blocksize,印证最后的block是没有foot block size记录块的!

测试demo:

/************************************************************************
code writer : EOF
code date : 2014.07.28
e-mail: jasonleaster@gmail.com

code purpose :
        test the block-size of each memory block which was allocated by
library function -- malloc().
        
        If there are something wrong with my code, please touch me by e-mail
or send me a message to my blog in CSDN. Thank you.
 
*************************************************************************/

#include <stdio.h>
#include <stdlib.h>

#define MACHINE_BITS    64      //the bits of this machine
#define BYTE            8       //one byte == eight bits

#define ALLOCATED_OR_NOT(bp)    ((unsigned long)(bp) & 0x1)
//@bp : block pointer which point into the start location of this block

#define GET_VALUE_LONG(ptr)             (*((long*)(ptr)))
//get the value of the location where ptr point to.

#define BLOCK_SIZE(bp)          ((GET_VALUE_LONG(bp))&(~0x7))
//get the block size

int main()
{
        void* ptr_void = malloc(sizeof(int));//allocate the first block.

        printf("ptr_void:%p\n",ptr_void);

        void* foo_void = malloc(sizeof(int));//allocate the second block.

        printf("foo_void:%p\n",foo_void);


        long block_size = BLOCK_SIZE((char*)ptr_void-(MACHINE_BITS/BYTE));//get the first block's header-block-size

        printf("ptr_void header size:%ld\n",block_size);
        printf("ptr_void foot   size:%ld\n",BLOCK_SIZE((char*)ptr_void+block_size-(MACHINE_BITS/BYTE)));
        //print out the foot-block-size


        block_size = BLOCK_SIZE((char*)foo_void-(MACHINE_BITS/BYTE));

        printf("foo_void header size:%ld\n",block_size);
        printf("foo_void foot   size:%ld\n",BLOCK_SIZE((char*)foo_void+block_size-(MACHINE_BITS/BYTE)));

        free(ptr_void);
        free(foo_void);
        return 0;
}





Malloc Lab是一个实验项目,要求我们实现一个动态内存分配器,使其具有与标准C库中的malloc、free、realloc函数相同的功能。我们需要自行定义块的空间结构,并实现find_fit函数和place函数,这两个函数都涉及到指针的操作,需要特别注意,以避免出现BUG。 在实现动态内存分配器时,我们需要考虑以下几个方面: 1. 内存块的分配和释放:我们需要实现malloc和free函数,前者用于分配内存块,后者用于释放内存块。 2. 内存块的合并:当一个内存块被释放时,我们需要将其与相邻的空闲块合并,以便后续的内存分配。 3. 内存块的查找:在分配内存块时,我们需要查找一个合适的空闲块,以满足用户的需求。 以下是一个简单的动态内存分配器的实现,仅供参考: ```c /* Basic constants and macros */ #define WSIZE 4 /* Word and header/footer size (bytes) */ #define DSIZE 8 /* Double word size (bytes) */ #define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */ /* Pack a size and allocated bit into a word */ #define PACK(size, alloc) ((size) | (alloc)) /* Read and write a word at address p */ #define GET(p) (*(unsigned int *)(p)) #define PUT(p, val) (*(unsigned int *)(p) = (val)) /* Read the size and allocated fields from address p */ #define GET_SIZE(p) (GET(p) & ~0x7) #define GET_ALLOC(p) (GET(p) & 0x1) /* Given block ptr bp, compute address of its header and footer */ #define HDRP(bp) ((char *)(bp) - WSIZE) #define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) /* Given block ptr bp, compute address of next and previous blocks */ #define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) #define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) /* Global variables */ static char *heap_listp = 0; /* Function prototypes for internal helper routines */ static void *extend_heap(size_t words); static void *coalesce(void *bp); static void *find_fit(size_t asize); static void place(void *bp, size_t asize); /* * mm_init - Initialize the memory manager */ int mm_init(void) { /* Create the initial empty heap */ if ((heap_listp = mem_sbrk(4*WSIZE)) == (void *)-1) return -1; PUT(heap_listp, 0); /* Alignment padding */ PUT(heap_listp + (1*WSIZE), PACK(DSIZE, 1)); /* Prologue header */ PUT(heap_listp + (2*WSIZE), PACK(DSIZE, 1)); /* Prologue footer */ PUT(heap_listp + (3*WSIZE), PACK(0, 1)); /* Epilogue header */ heap_listp += (2*WSIZE); /* Extend the empty heap with a free block of CHUNKSIZE bytes */ if (extend_heap(CHUNKSIZE/WSIZE) == NULL) return -1; return 0; } /* * mm_malloc - Allocate a block with at least size bytes of payload */ void *mm_malloc(size_t size) { size_t asize; /* Adjusted block size */ size_t extendsize; /* Amount to extend heap if no fit */ char *bp; /* Ignore spurious requests */ if (size == 0) return NULL; /* Adjust block size to include overhead and alignment reqs. */ if (size <= DSIZE) asize = 2*DSIZE; else asize = DSIZE * ((size + (DSIZE) + (DSIZE-1)) / DSIZE); /* Search the free list for a fit */ if ((bp = find_fit(asize)) != NULL) { place(bp, asize); return bp; } /* No fit found. Get more memory and place the block */ extendsize = MAX(asize, CHUNKSIZE); if ((bp = extend_heap(extendsize/WSIZE)) == NULL) return NULL; place(bp, asize); return bp; } /* * mm_free - Free a block */ void mm_free(void *bp) { size_t size = GET_SIZE(HDRP(bp)); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); coalesce(bp); } /* * mm_realloc - naive implementation of mm_realloc */ void *mm_realloc(void *ptr, size_t size) { void *newptr; size_t copySize; /* If size == 0 then this is just free, and we return NULL. */ if (size == 0) { mm_free(ptr); return 0; } /* If oldptr is NULL, then this is just malloc. */ if (ptr == NULL) { return mm_malloc(size); } newptr = mm_malloc(size); /* If realloc() fails the original block is left untouched */ if (!newptr) { return 0; } /* Copy the old data. */ copySize = GET_SIZE(HDRP(ptr)); if (size < copySize) { copySize = size; } memcpy(newptr, ptr, copySize); /* Free the old block. */ mm_free(ptr); return newptr; } /* * extend_heap - Extend heap with free block and return its block pointer */ static void *extend_heap(size_t words) { char *bp; size_t size; /* Allocate an even number of words to maintain alignment */ size = (words % 2) ? (words+1) * WSIZE : words * WSIZE; if ((long)(bp = mem_sbrk(size)) == -1) return NULL; /* Initialize free block header/footer and the epilogue header */ PUT(HDRP(bp), PACK(size, 0)); /* Free block header */ PUT(FTRP(bp), PACK(size, 0)); /* Free block footer */ PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); /* New epilogue header */ /* Coalesce if the previous block was free */ return coalesce(bp); } /* * coalesce - Boundary tag coalescing. Return ptr to coalesced block */ static void *coalesce(void *bp) { size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp))); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); if (prev_alloc && next_alloc) { /* Case 1 */ return bp; } else if (prev_alloc && !next_alloc) { /* Case 2 */ size += GET_SIZE(HDRP(NEXT_BLKP(bp))); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size,0)); } else if (!prev_alloc && next_alloc) { /* Case 3 */ size += GET_SIZE(HDRP(PREV_BLKP(bp))); PUT(FTRP(bp), PACK(size, 0)); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } else { /* Case 4 */ size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(FTRP(NEXT_BLKP(bp))); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } return bp; } /* * find_fit - Find a fit for a block with asize bytes */ static void *find_fit(size_t asize) { void *bp; for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (!GET_ALLOC(HDRP(bp)) && (asize <= GET_SIZE(HDRP(bp)))) { return bp; } } return NULL; /* No fit */ } /* * place - Place block of asize bytes at start of free block bp * and split if remainder would be at least minimum block size */ static void place(void *bp, size_t asize) { size_t csize = GET_SIZE(HDRP(bp)); if ((csize - asize) >= (2*DSIZE)) { PUT(HDRP(bp), PACK(asize, 1)); PUT(FTRP(bp), PACK(asize, 1)); bp = NEXT_BLKP(bp); PUT(HDRP(bp), PACK(csize-asize, 0)); PUT(FTRP(bp), PACK(csize-asize, 0)); } else { PUT(HDRP(bp), PACK(csize, 1)); PUT(FTRP(bp), PACK(csize, 1)); } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值