Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding where a shared_ptr's reference count is incremented

I have some code which has memory leaks as it is getting cycling references among its shared_ptr instances (this is where two shared_ptr instances point to objects which each have an internal shared_ptr reference to the other class instance. This means neither class will ever get destroyed, as each class instance is still in use by the other one, causing a memory leak. In some cases it is a single shared_ptr instance of a class that references itself, also.)

Running the code through Valgrind is helpful as it tells me where the memory was originally allocated, however this is not where the cyclic reference originates. I need to find all the places that a specific shared pointer (the one Valgrind complains about) has had its reference count incremented, as one of those will have to be changed to a weak_ptr to solve the problem.

How can I select a specific shared_ptr and get a list of all source lines where its reference count was incremented?

I'm running under Linux with GCC/GDB and Valgrind, but platform-neutral solutions would be welcomed.

Here is some sample code to demonstrate the problem:

#include <boost/shared_ptr.hpp>

struct Base {
    int i;
};
struct A: public Base {
    int a;
    boost::shared_ptr<Base> ptrInA;
};
struct B: public Base {
    int b;
    boost::shared_ptr<Base> ptrInB;
};

int main(void)
{
    boost::shared_ptr<A> a(new A);   // Line 17
    boost::shared_ptr<B> b(new B);
    a->ptrInA = b;                   // Line 19
    b->ptrInB = a;
    return 0;
}

When run under Valgrind, it says:

HEAP SUMMARY:
    in use at exit: 96 bytes in 4 blocks
  total heap usage: 4 allocs, 0 frees, 96 bytes allocated

96 (24 direct, 72 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
   at 0x4C2A4F0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x40099A: main (test.cpp:17)

LEAK SUMMARY:
   definitely lost: 24 bytes in 1 blocks
   indirectly lost: 72 bytes in 3 blocks

I'm looking for a solution that would point me to lines 19-20 in the source file as possible causes of the cycle, so I can examine the code and make a decision about whether it needs to be changed.

like image 424
Malvineous Avatar asked Feb 03 '15 04:02

Malvineous


People also ask

What is a shared_ptr in C++?

A shared_ptr is a container for raw pointers. It is a reference counting ownership model i.e. it maintains the reference count of its contained pointer in cooperation with all copies of the shared_ptr. So, the counter is incremented each time a new pointer points to the resource and decremented when the destructor of the object is called.

What is the use Count of an empty shared pointer?

After a shared pointer has been moved from, it shall be empty. The use count of an empty shared pointer is 0.

What happens when a shared_ptr is constructed from an existing pointer?

If a shared_ptr is constructed from an existing pointer that is not shared_ptr the memory for the control structure has to be allocated. This Control block is destroyed and deallocated when the last weak ref goes away. A shared_ptr construction approach takes two steps

What is a counter in a shared_ptr?

It is a reference counting ownership model i.e. it maintains the reference count of its contained pointer in cooperation with all copies of the shared_ptr. So, the counter is incremented each time a new pointer points to the resource and decremented when the destructor of the object is called.


1 Answers

You have a design error. And as such, you need to use design debugging tools.

Get a Pen and a piece of Paper.
Draw a rectangle for each class type. Draw an arrow from every class that holds a shared_ptr to the class it holds.
If you find a circle, that's your problem.

Now, each arrow, or link, is created somewhere via shared_ptr assignment.
Look at the suspicious arrows, those that close the circle, and see if they are released properly.

like image 68
Yochai Timmer Avatar answered Sep 23 '22 16:09

Yochai Timmer