Difference between revisions of "HOWTO resolve circular references in ns-3 memory disposal"
From Nsnam
(→HOWTO resolve smart pointer circular references in ns-3 memory disposal) |
(→HOWTO resolve smart pointer circular references in ns-3 memory disposal) |
||
Line 60: | Line 60: | ||
==16877== possibly lost: 0 bytes in 0 blocks | ==16877== possibly lost: 0 bytes in 0 blocks | ||
− | + | An explicit call to Dispose() is not always necessary. Before the simulator exits, Dispose() is called on all ns-3 nodes. Therefore if your object is aggregated onto a node or aggregated onto something that is aggregated onto a node etc., explicitly calling Dispose is not necessary. | |
+ | |||
+ | For example: | ||
+ | <pre> | ||
+ | int main(int argc, char* argv[]) | ||
+ | { | ||
+ | Ptr<A> a = CreateObject<A>(); | ||
+ | Ptr<B> b = CreateObject<B>(); | ||
+ | Ptr<Node> node = CreateObject<Node>(); | ||
+ | a->m_callback = MakeCallback (&B::CallbackMethodB, b); | ||
+ | b->AggregateObject(a); | ||
+ | node->AggregateObject(b); | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | An explicit call to Dispose is not necessary here. | ||
+ | |||
+ | ==17541== LEAK SUMMARY: | ||
+ | ==17541== definitely lost: 0 bytes in 0 blocks | ||
+ | ==17541== indirectly lost: 0 bytes in 0 blocks | ||
+ | ==17541== possibly lost: 0 bytes in 0 blocks |
Revision as of 18:20, 30 August 2013
HOWTO resolve smart pointer circular references in ns-3 memory disposal
class A : public Object { public: static TypeId GetTypeId (void); Callback<void> m_callback; }; class B : public Object { public: static TypeId GetTypeId (void); void CallbackMethodB (void); };
int main(int argc, char* argv[]) { Ptr<A> a = CreateObject<A>(); Ptr<B> b = CreateObject<B>(); a->m_callback = MakeCallback (&B::CallbackMethodB, b); b->AggregateObject(a); }
==15749== LEAK SUMMARY: ==15749== definitely lost: 40 bytes in 1 blocks ==15749== indirectly lost: 152 bytes in 5 blocks ==15749== possibly lost: 0 bytes in 0 blocks
The preferred way to break reference cycles like this in ns-3 is to use Object::Dispose(). This method will call the DoDispose method on the object that it is called on as well as all other objects aggregated on to it. In the above example Class A is aggregated to Class B so we make the following change to Class A:
class A : public Object { public: static TypeId GetTypeId (void); Callback<void> m_callback; virtual void DoDispose (void) { m_callback = MakeNullCallback<void>(); } };
Now the following code:
int main(int argc, char* argv[]) { Ptr<A> a = CreateObject<A>(); Ptr<B> b = CreateObject<B>(); a->m_callback = MakeCallback (&B::CallbackMethodB, b); b->AggregateObject(a); b->Dispose(); //a->Dispose() will work as well. Both will end up calling DoDispose //in object 'a' which breaks the reference cycle }
will no longer have a memory leak.
==16877== LEAK SUMMARY: ==16877== definitely lost: 0 bytes in 0 blocks ==16877== indirectly lost: 0 bytes in 0 blocks ==16877== possibly lost: 0 bytes in 0 blocks
An explicit call to Dispose() is not always necessary. Before the simulator exits, Dispose() is called on all ns-3 nodes. Therefore if your object is aggregated onto a node or aggregated onto something that is aggregated onto a node etc., explicitly calling Dispose is not necessary.
For example:
int main(int argc, char* argv[]) { Ptr<A> a = CreateObject<A>(); Ptr<B> b = CreateObject<B>(); Ptr<Node> node = CreateObject<Node>(); a->m_callback = MakeCallback (&B::CallbackMethodB, b); b->AggregateObject(a); node->AggregateObject(b); }
An explicit call to Dispose is not necessary here.
==17541== LEAK SUMMARY: ==17541== definitely lost: 0 bytes in 0 blocks ==17541== indirectly lost: 0 bytes in 0 blocks ==17541== possibly lost: 0 bytes in 0 blocks