2

I am trying to understand how memory is allocated as the number of objects increases. Following test program creates 400million objects and its memory occupancy is approximately 23GB.

Why would it occupy such huge memory while the single object size is just 16 bytes. Ideally i would assume it should be 16bytes multiplied by 400million.

    struct class1 {
        long long id;
        double value=0.0;
        class1(long long id) {
                this.id = id;
        }
};

for (int i=1;i<=400000000;i++) {
    class1 *t = new class1(i);
}
Nick
  • 375
  • 1
  • 2
  • 9
  • 1
    Dynamically allocated blocks typically round up their size (so your usable size is actually usually somewhat larger than what the new operator asked for) and add a little bit of management data overhead. The dynamically allocated are usually quite spread out too (bad cache locality), which is another reason why it's a good idea to allocate as much in one new/malloc call as you can. – Petr Skocik May 22 '17 at 20:56
  • 1
    You'll have to look into class footprint (see https://stackoverflow.com/questions/937773/how-do-you-determine-the-size-of-an-object-in-c ), padding, and also look into compiler flags. – ioan May 22 '17 at 20:59
  • 1
    Memory space tends to get fragmented when you do lots of small allocations. Also, your memory allocator may be allocating larger chunks at a time than just 16bytes (like a page at a time). Also, your class may not be just 16 bytes -there may be padding in there (+ allocator overhead). The good news is that if you don't *write* to the memory then the OS won't actuały back the allocation with physical pages (at least the Linux kernel won't) so it doesn't cost anything. – Jesper Juhl May 22 '17 at 21:00
  • I dont see this problem when i try with smaller number of objects (like ~40 objects). Whats puzzling is even with the extra padding and overhead you think it still occupy 3 times the expected size? I am using ubuntu. not sure if switching the OS would have made any difference? – Nick May 22 '17 at 21:23
  • Try using optimisation flags - see https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Optimize-Options.html – ioan May 22 '17 at 21:25

2 Answers2

2

If the question is how to write the program with the same number of objects and a reduced memory footprint, the answer is to overload the new and delete operators and write your own allocator that is specialised in doling out blocks of 16 bytes from large pools.

The general purpose allocator is inefficient because it is general purpose, and it is written to be fast rather than to save memory when allocating small objects. Most programs don't stress machine capacity with millions of small allocations.

Malcolm McLean
  • 6,258
  • 1
  • 17
  • 18
0

Every allocation has with it a "header" which includes extra information about the block. It definitely included the size of the block (so a "delete" know how much menory to free), a free saying if the block is free or allocated, the number of elements in the array (if it's an array) and so further.

Allocation two blocks, and subtract their pointers, and you should get the actual size taken up by each block.

Then, allocate a large array of these objects (say 100,000), and then just one, and subtract those pointers. That should show something closer to the 16 * 100,000 size, as that block would have only one header.

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 1
    That's allocator specific. You can't just say "that's how it is" without naming the specific allocator you are talking about. – Jesper Juhl May 22 '17 at 21:05
  • I was speaking in generalites. The specifics may vary, but nearly all allocators will work roughly like that. – James Curran May 22 '17 at 21:24