Last week I mentioned I’m going to start focusing on Windows specific APIs for Memory Allocation. Well, the time has come to fullfil my promise :)
This article will pretty much try to answer the question I had a while ago - “what really happens (in Windows) when you type keyword ‘new’” (e.g. new CandyBar()).
As usual, the bite-sized graphic first and additional details below it.
(click on image to expand)
As you see, both C++ and C (and I’d presume Rust and any other language runtime) eventually end up calling the Heap API (strictly speaking, “keyword new” calls “operator new” which in turn calls “malloc()” which eventually ends up calling “HeapAlloc”). Heap API is the main interface that Windows provides in order to allocate SINGLE BYTES.
Why do I say “Single Bytes”? Because once you go past the Heap API (i.e. once you go one level below) you end up in in VirtualAlloc (i.e. Memory API) which works in PAGES. What that means is that on this level you can only allocate MEMORY PAGES, which are ~4KBs in size.
If you’re not really familiar with Heap and Memory API, that’s totally fine. I will be digging deeper into them in the next articles!
Now why is all of this important, interesting or relevant at all? Why in the god’s name would you ever interact with HeapAlloc or VirtualAlloc instead of using ol’ good keyword new? And the truth is - if you’re asking this question, you likely won’t need to do it. But here’s the thing - C++ is built to run on ANY platform and that means that “new” has to be universal enough to be compileable for any underlying OS. Which further means that it has to be more on the generic side, which eventually means that it can’t provide support for some OS specific things and tweaks.
On the other hand, given the fact that HeapAlloc and VirtualAlloc are Windows-specific APIs, they support pretty much anything that you can ask Windows to do, some of those things being:
Heap API allows you to create private Heaps and ask HeapAlloc to allocate bits from those places
You can disable thread-safety and serialized access by specifying the HEAP_NO_SERIALIZE flag
Memory API’s VirtualAlloc allows you even greater control - you can ask to RESERVE memory without committing it, you can do some tweaks on address ranges where memory is being reserved, etc.
Generally speaking, possibilities are endless and you can pretty much fine-tune HOW you allocate the memory and make it fit your use-case. However, do remain mindful of the fact that with great power comes great responsibility.
Finally, in case you are wondering HOW you can actually see this in action - it’s quite simple. Fire up the Visual Studio, write some simple code that uses the “new” keyword (e.g. int* foo = new int(10);
) set a breakpoint at that line, go to Disassembly window and just follow what happens:
And that’s about it. Go try and experiment with it!
Next time I’m going to talk more about Heap API and HeapAlloc. Until then, do let me know if you found this article useful. You’d also help me if you spread the word by sharing it with your friends and colleagues:
Thanks for reading!
Other articles from the C++ Memory Management series: