2

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?

trincot
  • 317,000
  • 35
  • 244
  • 286
rkt
  • 1,171
  • 2
  • 9
  • 18
  • 4
    That's **undefined behaviour** and implementation dependent. – pmg Aug 15 '12 at 20:07
  • We can possibly give you some kind of answer if you tell us what version compiler you're using, your architecture, and your particular implementation of malloc. – Falmarri Aug 15 '12 at 20:11
  • That's an interesting assumption, and I hope you're asking just out of curiosity and not trying to use that anywhere. On my amd64 system, after replacing `int` with `size_t`, I get `817` (vs `800` requested); but with smaller counts the number's off either more or less. – Michał Górny Aug 15 '12 at 20:13
  • yeah..asked it just out of curiosity. Actually I have used this website ideone.com to run this code. I haven't checked with other compilers. – rkt Aug 15 '12 at 20:16

2 Answers2

6

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.

Michał Górny
  • 18,713
  • 5
  • 53
  • 76
0

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.

MSN
  • 53,214
  • 7
  • 75
  • 105