views:

536

answers:

2

I've got a number of reference counted classes in some of my applications, and also in dlls those applications use, all inheriting from and implementing a IRefCounted interface.

In order to help with finding the source of these memory leaks I want each application to maintain a list of all these refrence counted classes in existance.

The problem is the managing of instances of these lists such that their useage does not effect the usage of my classes (eg I don't need to pass a pointer to a list around all the time, instead somehow attaching it to the process).

-Theres a good chance several of these applications may be running at once, and using the same dll. Each application needs its own object list, and all the dlls etc loaded by that application need to use that list (but rember that one dll may be loaded by multiple applications...).
-The list must be destroyed after every other global and static variable in application, so the objects left in the list when its destructed are ones that truley were not correctly releashed.

I then will simply add a breakpoint to the list's destructor so I can look through any unallocated objects in the debugger.

+1  A: 

I'm guessing you're using COM. You'll probably need to find some way of having a weak pointer so that the registry of instantiated objects doesn't prevent them from being destructed.

If you can modify all the classes, you could inject a static member to keep track of all instances and have the destructor of an instance remove itself from the static member. For example, you could use a base class or utility class like the following:

class InstanceRegistry {
protected:
    InstanceRegistry() {
       registry.insert(this);
    }
    ~InstanceRegistry() {
       registry.remove(this);
    }
private:
  static SomeContainerType<InstanceRegistry*> registry;
};

Extra work would need to be done if you want a different registry for different types of classes, etc.

Mr Fooz
I'm not using COM, and I could add something to the con/destructor of the objects to add remove them from the list. The list probs shouldnt have a ref to the objects.
Fire Lancer
COM uses IUnknown, not IRefCounted.
jeffamaphone
Thanks. The COM note has been struck out.
Mr Fooz
+1  A: 

If processes are using the same DLL, each process gets its own private copy of that DLL's static (or "global") data.

So all you need to do is make the list be a global variable in a DLL, and link to that DLL from every application. That way, there is no need to pass anything additional around.

Your idea of trapping the destruction of the list is fraught with difficulties, due to the unpredictability of the order of destruction of objects in a multi-DLL process.

It would be a lot simpler to dump out the contents of the list at the end of your main or WinMain function.

If you're not using a smart pointer class in a consistent fashion, then do so. Also, it may be worth looking for cyclic reference counts - object A has a count on object B, and vice verse. This is a common cause of unreleased objects.

Update:

To force all static destructors to run and release objects, so you can then examine the entries in the list afterwards, you'll need to structure your application a certain way.

Suppose you have a very minimal EXE that launches the process, and loads a number of other DLLs that actually do all the work. These other DLLs are loaded with LoadLibrary, somehow (maybe by COM or a COM-like system). The LoadLibrary API works by either loading the DLL into the process, or else incrementing an internal reference counter on the DLL if it is already loaded. The FreeLibrary API decrements the counter until it reaches zero and then unloads the DLL (at which point the static destructors for that DLL will execute).

To this we now add our diagnostic DLL that holds a list of all outstanding reference counted objects. All the other DLLs use import-lib linkage to the diagnostic DLL, and the EXE uses LoadLibrary on it as well.

When main is about to exit, the EXE goes through the list of DLL handles it previously loaded, and calls FreeLibrary on all of them. By keeping the diagnostic DLL loaded, it ensures it's still there at the end. That's the theory at least.

But in what order should the other DLLs be unloaded? If A.DLL has static pointers to objects defined in B.DLL, then you better unload A first. So you need to have some idea of how your various DLLs form a "layered" architecture, with higher layers depending on lower layers, thus giving you a safe order in which to unload them.

Also, once you've unloaded all the DLLs, any entries in the diagnostic list that refer to objects in the DLLs will now be pointing to valid data on the heap, but the vtable will be pointing at code that was defined by the DLLs that have now been unloaded, so you won't be able to call virtual functions on those objects. You should be able to examine their data though.

Daniel Earwicker
The problem with dumping the list at the end of winmain is that any static or global smart pointers will still have refrences, which is perfectly safe since they will release the object when their destructed. So I really need to see the state of this list after any such smart pointers are destructed
Fire Lancer
Fine, except that 99% of static and global variables are in the .exe module, which still seems to be unloaded after the list is.
Fire Lancer
I guess I could build the apps as dlls, and have a host exe that contains the list, loads the app, calls WinMain in that app and then unloads and dumps the list when WinMain returns?
Fire Lancer
That's right - you would need to reorganize the app, because it's the only way you'll be able to dictate the order of unloading. Ideally you would have avoided statics altogether but I doubt you want to hear that now! :)
Daniel Earwicker