Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find how much memory is actually used up by a malloc call?

If I call:

char *myChar = (char *)malloc(sizeof(char));

I am likely to be using more than 1 byte of memory, because malloc is likely to be using some memory on its own to keep track of free blocks in the heap, and it may effectively cost me some memory by always aligning allocations along certain boundaries.

My question is: Is there a way to find out how much memory is really used up by a particular malloc call, including the effective cost of alignment, and the overhead used by malloc/free?

Just to be clear, I am not asking to find out how much memory a pointer points to after a call to malloc. Rather, I am debugging a program that uses a great deal of memory, and I want to be aware of which parts of the code are allocating how much memory. I'd like to be able to have internal memory accounting that very closely matches the numbers reported by top. Ideally, I'd like to be able to do this programmatically on a per-malloc-call basis, as opposed to getting a summary at a checkpoint.

like image 646
Tyler Avatar asked Dec 01 '11 01:12

Tyler


2 Answers

There isn't a portable solution to this, however there may be operating-system specific solutions for the environments you're interested in.

For example, with glibc on Linux, you can use the mallinfo() function from <malloc.h> which returns a struct mallinfo. The uordblks and hblkhd members of this structure contains the dynamically allocated address space used by the program including book-keeping overhead - if you take the difference of this before and after each malloc() call, you will know the amount of space used by that call. (The overhead is not necessarily constant for every call to malloc()).

Using your example:

char *myChar;
size_t s = sizeof(char);
struct mallinfo before, after;
int mused;

before = mallinfo();
myChar = malloc(s);
after = mallinfo();

mused = (after.uordblks - before.uordblks) + (after.hblkhd - before.hblkhd);

printf("Requested size %zu, used space %d, overhead %zu\n", s, mused, mused - s);

Really though, the overhead is likely to be pretty minor unless you are making a very very high number of very small allocations, which is a bad idea anyway.

like image 60
caf Avatar answered Oct 21 '22 14:10

caf


It really depends on the implementation. You should really use some memory debugger. On Linux Valgrind's Massif tool can be useful. There are memory debugging libraries like dmalloc, ...

That said, typical overhead:

  • 1 int for storing size + flags of this block.
  • possibly 1 int for storing size of previous/next block, to assist in coallescing blocks.
  • 2 pointers, but these may only be used in free()'d blocks, being reused for application storage in allocated blocks.
  • Alignment to an approppriate type, e.g: double.
  • -1 int (yes, that's a minus) of the next/previous chunk's field containing our size if we are an allocated block, since we cannot be coallesced until we're freed.

So, a minimum size can be 16 to 24 bytes. and minimum overhead can be 4 bytes.

But you could also satisfy every allocation via mapping memory pages (typically 4Kb), which would mean overhead for smaller allocations would be huge. I think OpenBSD does this.

like image 39
ninjalj Avatar answered Oct 21 '22 12:10

ninjalj