Current message queue is not cleared when update is destroyed
This is 1 cause of Node leak.
Second cause of Node leak is InstallRootMessage passes a layer
as a raw pointer. If update doesn't run ( doesn't run in the test
cases), then we leak the layer (node).
Also added DEBUG_ASSERT to check for leaking scene graph Nodes
Change-Id: Ibfbb73ee840cbeaf33104da6769945cf9b3aafbc
inline void InstallRootMessage( UpdateManager& manager, Layer& root, bool systemLevel )
{
inline void InstallRootMessage( UpdateManager& manager, Layer& root, bool systemLevel )
{
- typedef MessageValue2< UpdateManager, Layer*, bool > LocalType;
+ // Message has ownership of Layer while in transit from event -> update
+ typedef MessageValue2< UpdateManager, OwnerPointer<Layer>, bool > LocalType;
// Reserve some memory inside the message queue
unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
// Reserve some memory inside the message queue
unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
inline void AddNodeMessage( UpdateManager& manager, Node& node )
{
inline void AddNodeMessage( UpdateManager& manager, Node& node )
{
+ // Message has ownership of Node while in transit from event -> update
typedef MessageValue1< UpdateManager, OwnerPointer<Node> > LocalType;
// Reserve some memory inside the message queue
typedef MessageValue1< UpdateManager, OwnerPointer<Node> > LocalType;
// Reserve some memory inside the message queue
//Memory pool used to allocate new nodes. Memory used by this pool will be released when process dies
// or DALI library is unloaded
Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Node> gNodeMemoryPool;
//Memory pool used to allocate new nodes. Memory used by this pool will be released when process dies
// or DALI library is unloaded
Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Node> gNodeMemoryPool;
+#ifdef DEBUG_ENABLED
+// keep track of nodes created / deleted, to ensure we have 0 when the process exits or DALi library is unloaded
+int gNodeCount =0;
+
+// Called when the process is about to exit, Node count should be zero at this point.
+void __attribute__ ((destructor)) ShutDown(void)
+{
+DALI_ASSERT_DEBUG( (gNodeCount == 0) && "Node memory leak");
+}
+#endif
{
mUniformMapChanged[0] = 0u;
mUniformMapChanged[1] = 0u;
{
mUniformMapChanged[0] = 0u;
mUniformMapChanged[1] = 0u;
+
+#ifdef DEBUG_ENABLED
+ gNodeCount++;
+#endif
+
{
mTransformManager->RemoveTransform(mTransformId);
}
{
mTransformManager->RemoveTransform(mTransformId);
}
+
+#ifdef DEBUG_ENABLED
+ gNodeCount--;
+#endif
} // namespace SceneGraph
} // namespace SceneGraph
+template <>
+void OwnerPointer<Dali::Internal::SceneGraph::Layer>::Reset()
+{
+ if( mObject != NULL )
+ {
+ Dali::Internal::SceneGraph::Node::Delete( mObject );
+ mObject = NULL;
+ }
+}
} // namespace Internal
} // namespace Dali
} // namespace Internal
} // namespace Dali
} // namespace SceneGraph
} // namespace SceneGraph
+// Template specialisation for OwnerPointer<Layer>, because delete is protected
+template <>
+void OwnerPointer<Dali::Internal::SceneGraph::Layer>::Reset();
+
} // namespace Internal
} // namespace Dali
} // namespace Internal
} // namespace Dali
~Impl()
{
// Delete the current buffer
~Impl()
{
// Delete the current buffer
- delete currentMessageBuffer;
+ if( currentMessageBuffer )
+ {
+ DeleteBufferContents( currentMessageBuffer );
+ delete currentMessageBuffer;
+ }
// Delete the unprocessed buffers
const MessageBufferIter processQueueEndIter = processQueue.end();
// Delete the unprocessed buffers
const MessageBufferIter processQueueEndIter = processQueue.end();