views:

159

answers:

5

I have an object which implements reference counting mechanism. If the number of references to it becomes zero, the object is deleted.

I found that my object is never deleted, even when I am done with it. This is leading to memory overuse. All I have is the number of references to the object and I want to know the places which reference it so that I can write appropriate cleanup code.

Is there some way to accomplish this without having to grep in the source files? (That would be very cumbersome.)

A: 

I don't think it's possible to do something without code change. With code change you can for example remember the pointers of the objects which increase reference count, and then see what pointer is left and examine it in the debugger. If possible - store more verbose information, such as object name.

Drakosha
+6  A: 

A huge part of getting reference counting (refcounting) done correctly in C++ is to use Resource Allocation Is Initialization so it's much harder to accidentally leak references. However, this doesn't solve everything with refcounts.

That said, you can implement a debug feature in your refcounting which tracks what is holding references. You can then analyze this information when necessary, and remove it from release builds. (Use a configuration macro similar in purpose to how DEBUG macros are used.)

Exactly how you should implement it is going to depend on all your requirements, but there are two main ways to do this (with a brief overview of differences):

  • store the information on the referenced object itself
    • accessible from your debugger
    • easier to implement
  • output to a special trace file every time a reference is acquired or released
    • still available after the program exits (even abnormally)
    • possible to use while the program is running, without running in your debugger
    • can be used even in special release builds and sent back to you for analysis

The basic problem, of knowing what is referencing a given object, is hard to solve in general, and will require some work. Compare: can you tell me every person and business that knows your postal address or phone number?

Roger Pate
+1  A: 

One known weakness of reference counting is that it does not work when there are cyclic references, i.e. (in the simplest case) when one object has a reference to another object which in turn has a reference to the former object. This sounds like a non-issue, but in data structures such as binary trees with back-references to parent nodes, there you are.

If you don't explicitly provide for a list of "reverse" references in the referenced (un-freed) object, I don't see a way to figure out who is referencing it.

In the following suggestions, I assume that you don't want to modify your source, or if so, just a little.

You could of course walk the whole heap / freestore and search for the memory address of your un-freed object, but if its address turns up, it's not guaranteed to actually be a memory address reference; it could just as well be any random floating point number, of anything else. However, if the found value lies inside a block a memory that your application allocated for an object, chances improve a little that it's indeed a pointer to another object.

One possible improvement over this approach would be to modify the memory allocator you use -- e.g. your global operator new -- so that it keeps a list of all allocated memory blocks and their sizes. (In a complete implementation of this, operator delete would have remove the list entry for the freed block of memory.) Now, at the end of your program, you have a clue where to search for the un-freed object's memory address, since you have a list of memory blocks that your program actually used.

The above suggestions don't sound very reliable to me, to be honest; but maybe defining a custom global operator new and operator delete that does some logging / tracing goes in the right direction to solve your problem.

stakx
One day a student came to Moon and said, "I understand how to make a better garbage collector. We must keep a reference count of the pointers to each cons." Moon patiently told the student the following story: "One day a student came to Moon and said, 'I understand how to make a better garbage collector...'" (http://www.serve.com/cmtan/buddhism/Lighter/aikoans.html, http://en.wikipedia.org/wiki/Hacker_koan)
outis
The simplest case is an object that has a reference to itself. :) (This isn't a pathological case either, consider any class that uses `delete this`.)
Roger Pate
A: 

I have created one for my needs. You can compare your code with this one and see what's missing. It's not perfect but it should work in most of the cases. http://sites.google.com/site/grayasm/autopointer

when I use it I do:

util::autopointer<A> aptr=new A();

I never do it like this:

A* ptr = new A();
util::autopointer<A> aptr = ptr; 

and later to start fulling around with ptr; That's not allowed. Further I am using only aptr to refer to this object. If I am wrong I have now the chance to get corrections. :) See ya!

grayasm
+1  A: 

I am assuming you have some class with say addRef() and release() member functions, and you call these when you need to increase and decrease the reference count on each instance, and that the instances that cause problems are on the heap and referred to with raw pointers. The simplest fix may be to replace all pointers to the controlled object with boost::shared_ptr. This is surprisingly easy to do and should enable you to dispense with your own reference counting - you can just make those functions I mentioned do nothing. The main change required in your code is in the signatures of functions that pass or return your pointers. Other places to change are in initializer lists (if you initialize pointers to null) and if()-statements (if you compare pointers with null). The compiler will find all such places after you change the declarations of the pointers.

If you do not want to use the shared_ptr - maybe you want to keep the reference count intrinsic to the class - you can craft your own simple smart pointer just to deal with your class. Then use it to control the lifetime of your class objects. So for example, instead of pointer assignment being done with raw pointers and you "manually" calling addRef(), you just do an assignment of your smart pointer class which includes the addRef() automatically.

Permaquid
Using objects which manage resources as an intrinsic part of their natural lifetime is called RAII.
Roger Pate
No reasonable person could disagree with that.
Permaquid