C++ Order Of Destruction
Me again [smile]
As some of you might know, I'm trying to write a memory manager for my engine. However, as I found last night, the STL keeps hold of some memory that is only freed when a global variable inside a STL source file is destroyed.
Now, I know that the order of construction / destruction isn't defined for global variables, and it appears that atexit() handlers fire before globals are destroyed.
What I'd like to know is, is there any way I can have a function called after globals have been destroyed? For instance, at what point are DLLs unloaded? I could put something in a DLL if it'll work. There was an article I read somewhere that covered the order things are created and destroyed (The article was about writing your own loader I think), but I can't find it now.
Platform specific answers are perfectly fine (Win32), I expect I'll need to do some crazy stuff to get this to work at all.
Cheers,
Steve
I don't have a solution for you, but I'm interested in knowing which part of the STL is holding that memory and when it got allocated. Could you tell a bit more about this issue?
Quote:Original post by El GrecoSure, I made a post about this last night in My GDNet Journal.
I don't have a solution for you, but I'm interested in knowing which part of the STL is holding that memory and when it got allocated. Could you tell a bit more about this issue?
IIRC theres a gcc extension which lets you specify the priority of globals to control their construction order. That should let you do what you want I think.
Obviously this is non-portable though.
I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.
Obviously this is non-portable though.
I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.
Quote:Original post by OrangyTangHmm, any idea if there's a MSVC version of that? I'll dig into the MSDN.
IIRC theres a gcc extension which lets you specify the priority of globals to control their construction order. That should let you do what you want I think.
Obviously this is non-portable though.
I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.
The globals being static in methods half works - but that causes the static to be created after the globals, meaning it's destroyed before them, which doesn't help.
The global in question is in STL code; I can't change that.
The first thing sounds exactly what I want, though.
Do you have vs/vc++2k5 SP1 installed? the reason i ask is vc++2k5's string streams have memory leaks and the SP1 sorts it out as well as many other issues of course.
EDIT: There is another SP (which you install after SP1) if you're runing vs/vc++2k5 on Vista.
EDIT: There is another SP (which you install after SP1) if you're runing vs/vc++2k5 on Vista.
Quote:Original post by snk_kidNope, I don't have SP1 installed. For some reason I thought that was only for Express.
Do you have vs/vc++2k5 SP1 installed? the reason i ask is vc++2k5's string streams have memory leaks and the SP1 sorts it out as well as many other issues of course.
EDIT: There is another SP (which you install after SP1) if you're runing vs/vc++2k5 on Vista.
Just checked my code at work (VC2005 Express, SP1) and it has the same "leaks". These aren;t really leaks, because they do get freed up. Just after my memory manager...
I'm not running Vista on my dev machine(s), so that's not an issue.
I'll poke around in your journal for the full story, but for what it's worth the way my old C++ memory tools worked was set up in such a way as to not track the memory allocated by the SC++L or other external tools, at least not explicitly; I only tracked allocations from code I actually wrote (which might include custom allocators to the SC++L objects, though).
I never ran into the problem you're describing, iirc. Although this was years ago, so perhaps the newer SC++L implementation shipping with modern compilers would exhibit the issue now.
EDIT: Okay. It's the call to new to allocate the facet (a facet is a term for an interface to a service provided by the locale library, for what it's worth) that is trapped by your manager and then reported as a leak, right?
The traditional, simple way to avoid this issue is to provide headers to enable/disable the #define macros you use to redirect new and delete (you do use macros for this, right?). It becomes a bit obnoxious to wrap your SC++L includes, or order them appropriately so they come into the translation unit before your macro, but it works. There are a few more way, possibly slightly cleaner, but they depend somewhat on the actual implementation detail of the system used to trap calls to new. Can you provide your code?
I never ran into the problem you're describing, iirc. Although this was years ago, so perhaps the newer SC++L implementation shipping with modern compilers would exhibit the issue now.
EDIT: Okay. It's the call to new to allocate the facet (a facet is a term for an interface to a service provided by the locale library, for what it's worth) that is trapped by your manager and then reported as a leak, right?
The traditional, simple way to avoid this issue is to provide headers to enable/disable the #define macros you use to redirect new and delete (you do use macros for this, right?). It becomes a bit obnoxious to wrap your SC++L includes, or order them appropriately so they come into the translation unit before your macro, but it works. There are a few more way, possibly slightly cleaner, but they depend somewhat on the actual implementation detail of the system used to trap calls to new. Can you provide your code?
Quote:Original post by jpetrieYeah, I chose to track STL allocations just so I'm catching everything.
I'll poke around in your journal for the full story, but for what it's worth the way my old C++ memory tools worked was set up in such a way as to not track the memory allocated by the SC++L or other external tools, at least not explicitly; I only tracked allocations from code I actually wrote (which might include custom allocators to the SC++L objects, though).
I never ran into the problem you're describing, iirc. Although this was years ago, so perhaps the newer SC++L implementation shipping with modern compilers would exhibit the issue now.
Anyway, I've solved it. Thanks to mattd (See, TA can be useful sometimes [smile])
#pragma init_seg is what I needed. Adding this code forces my memory manager to be created before and destroyed after STL globals:
#pragma warning(disable:4074) // warning C4074: initializers put in compiler reserved initialization area#pragma init_seg(compiler)struct MemoryInitialiser{ MemoryInitialiser() { PMemory::Create(); } ~MemoryInitialiser() { PMemory::Destroy(); }} g_theMemoryInitialiser;
Thanks to all who helped [smile]
Here are a few more solutions if anyone wants to stay away from compiler specific intrinsics.
1) Have the memory manager as a global object at the top of your main application. Obj files that are for the executable get initialized before library statics. Also, the the order of globals, within a compilation unit, are initialized from top down. If your memory manager is the first global variable in that file and doesn't depend, contain or inherit from any other class then you'll have it being initialized first.
2) The most portable way (I define portable being this has worked for me on the most platforms and most compilers) is to re-write the CRT initialization and shut down code. Have your own function get called instead of the CRT start up. You can do this through the linker option /ENTRY in visual studio. It's not too hard and most of the time you can copy and paste the compilers CRT code, remove the stuff you don't need, and stick your memory manager initialization before the global variables are constructed.
-= Dave
1) Have the memory manager as a global object at the top of your main application. Obj files that are for the executable get initialized before library statics. Also, the the order of globals, within a compilation unit, are initialized from top down. If your memory manager is the first global variable in that file and doesn't depend, contain or inherit from any other class then you'll have it being initialized first.
2) The most portable way (I define portable being this has worked for me on the most platforms and most compilers) is to re-write the CRT initialization and shut down code. Have your own function get called instead of the CRT start up. You can do this through the linker option /ENTRY in visual studio. It's not too hard and most of the time you can copy and paste the compilers CRT code, remove the stuff you don't need, and stick your memory manager initialization before the global variables are constructed.
-= Dave
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement