Private Heap DisasterFiled Under: Weekly Tuesday Dose of goodness
- Private Heap Disaster
- Debugging Disasters
- ‘this’ pointer disaster
- Inheritance disaster
Hi all,
This week I’ll be sharing an experience I had recently. Yes, recently despite my “10 years” of C++ experience. There’re still many more things that I do not know about C++ and have tried but failed to fully gasp its concepts properly.
And I think it’s fair to share knowledge gaps since everybody has their flaws. I hope that this article can help some if not help myself should the contents be flawed or inaccurate.
So, let’s have a look…
Introduction
Previously, I’ve mentioned that C++ has at least 4 types of memory.
- Stack
- Heap
- Code
- Static
Noticed that I’ve highlighted the static memory? Yes. It’s also known as the private heap. So what do we understand about static? One and only. Right?
Ermm well, if you’re talking about a single application, 32 or 64 bits, single or multi-threaded in C++, yeah it should be the one and only instance.
Note : This doesn’t fully apply to Java since I know that Java has other properties for static keyword.
But have we considered about DLLs and Shared Objects? Well, or rather, is there a real reason as to why static memory is known as a private heap as well? The answer well… it’s pretty simple - it’s private!
I’ll explain in greater details in a short while.
Disaster
A single pattern alone is usually insufficient to cause a disaster to happen. It takes a chain of misunderstandings, coincidences and misfortunes for a real disaster to happen. That also includes building up knowledge without sufficient application and execution of it.
So, let’s take a look at the ingredients shall we?
1) Meyer’s Singleton
2) Classes using that kind of singletons
3) Multiple DLLs compiled with that singleton
4) One or more classes in the individual DLLs use that singleton
5) Application links these DLLs at runtime
None of these individual items are at fault when you look at them individually. However, if you put them together, they become a big mess.
No, they may not necessarily crash your application during runtime, but it does some decent amount of damage to your designs if it’s not detected early.
What damage does it do? Well, since Meyer’s Singleton uses a single static instance of itself within a private constructor, no one has the direct rights to instantiate a singleton technically in C++ right? Well, at least that’s where all the ::getInstance() are coming from - you simply don’t instantiate singletons on your own.
Next, since, the only way to get the static object instantiated is by calling getInstance(), then it’ll be safe to say that if the application calls the ::getInstance() of a singleton ONCE and the rest will be using the SAME copy?
Disaster STRIKES!
The reason why static is known as the private heap is because these guys, while they’re known during compile time and also expected to be growing. (thus the heap and not the stack) However, it’s also private, that means that this instance only belongs to the very application that linked it.
Now we know, applications link, DLLs link, but static libraries don’t link. Therefore if a singleton is called based on a library that is linked to the application, it’ll still be the same copy.
However, if you notice, DLLs are complete applications as well (thus having the need to define DLLMain). This also means the whole DLL must be build-able and link-able in the end. Thus a unique copy of the singleton is now linked into the DLL.
So when you load an application that loads a DLL which both linked the same meyer’s singleton, what’s going to happen?
That’s right! There’ll be TWO SEPARATE COPIES of them.
While this is usually not a problem for singletons that does only the functional work and have none of the attributes, it’ll be a disaster for entity managers, repositories, etc, anything that can store global information.
Debugging
It’s near impossible to debug such a kind of problem since getInstance() refers to the same piece of code. So your usual breakpoint, step-in, step-thru and step-out will be almost useless.
But fear not, the watch is here to save you. But you must use manual entry watches, otherwise it’ll be invisible.
What you need to do is simple - as you step into the singleton’s getInstance() function, add the following into the watch:
this | 0x12341111
And you should get something like the one above. Now, repeat the same for the getInstance() that is called by your DLL codes, it’ll become something like:
this | 0xACDE1244
The problem lies in the need to call getInstance() everytime you retrieve a singleton, thus eliminating the possibly of a “hack” solution. Obviously, this shows 2 difference objects in different memory locations even when they appear to browse and point at the same piece of code.
Obstacles
This becomes a nightmare when using repository-based singletons such as the Bind Repository used by StridesLib to store all the bindings.
Since the user expects to be using the same instance when cBindRepository::getInstance() is called, this becomes exceptionally confusing and hard to understand when an obviously modified attribute doesn’t even show up on the game.
Conclusion
It’s extremely hard for anyone to debug such problems unless he/she has extensive understanding of the private heap and other C++ memory types.
I just hope that by sharing this experience, people out there can avoid making the same mistake as I did.
It’s very hard to justify why one must understand private heap only until it’s too late. The solution for my disaster was quite ugly but it works out anyway. Worse of all, many people don’t even know that private heap exists. They just know how to use it roughly and I tell you, the counter-effects of it can be as rough as sand rubbing your ASS!
Just remember, the one and only rule only works for a single application and it may not necessarily apply or work as expected with applications loading up DLLs especially when both the DLL and application seemingly use the same calling method - Singleton::getInstance().
Have a great week ahead!
Signing off,
Jeremy
- Permalink
- Admin
- 1 Jun 2010 9:59 AM
- Comments (0)