unexpected output of size allocated by malloc in C [closed]

断了今生、忘了曾经 提交于 2019-12-22 12:53:34

问题


I have read that malloc actually allocates (required_size + 1) blocks of memory and it stores the size in the first block and the pointer to the second block is returned. This way free() knows how much memory to free. So, I wrote a small code to output this size.

int *p = (int *)malloc(100*sizeof(int));
printf("size = %d\n",p[-1]);

Since I am allocating space for 100 ints, I am expecting the size to be 400. But the output was 409. For 50 int's output was 209 and for 1000 int's output was 4009. Can someone pls explain why the output is off by 9 bytes?


回答1:


Assuming the implementation is glibc (or similar), the following can be found in comments in malloc.c:

Minimum overhead per allocated chunk:   4 or 8 bytes
   Each malloced chunk has a hidden word of overhead holding size
   and status information.

Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)

   When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
   ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
   needed; 4 (8) for a trailing size field and 8 (16) bytes for
   free list pointers. Thus, the minimum allocatable size is
   16/24/32 bytes.

That explains the existence of overhead.

Now, for the 'off by 1', the flags are responsible for that. Since sizes (actually) allocated by malloc() will be always multiples of 8, the three least significant bits are used to store flags:

/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1

/* extract inuse bit of previous chunk */
#define prev_inuse(p)       ((p)->size & PREV_INUSE)


/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
#define IS_MMAPPED 0x2

/* check for mmap()'ed chunk */
#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)


/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
   from a non-main arena.  This is only set immediately before handing
   the chunk to the user, if necessary.  */
#define NON_MAIN_ARENA 0x4

/* check for chunk from non-main arena */
#define chunk_non_main_arena(p) ((p)->size & NON_MAIN_ARENA)

Edit: ah, and I'd almost forgot. The size is stored as size_t, not an int, so you should use that type to access it.




回答2:


If that value is the allocation size, aside from it being implementation dependent, I'll hazard a guess and say that you have a few possibilities for the extra 9.

The number is probably always going to be odd for unfreed allocations. Given that most operating systems have built-in memory allocation functions that return at a granularity higher than 1 byte, the implementation of malloc probably uses the first bit of the allocation size to track whether the allocation has been freed or not.

The malloc implementation is also either taking advantage of the natural alignment of allocations returned by the operating system, that is, rounding up the actual allocation size to the alignment guaranteed by the operating system (which would account for the additional 8 bytes), or it also allocates 4 bytes at the end of the allocation to use as a guard value.

However, you can learn more about where the allocation information is stored from the documentation for the platform and compiler you are using.



来源:https://stackoverflow.com/questions/11976414/unexpected-output-of-size-allocated-by-malloc-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!