Fix Message Buffer leak and added DEBUG_ASSERT for leaking nodes 87/116687/9
authorNick Holland <nick.holland@partner.samsung.com>
Mon, 27 Feb 2017 15:11:26 +0000 (15:11 +0000)
committerNick Holland <nick.holland@partner.samsung.com>
Thu, 2 Mar 2017 11:07:04 +0000 (11:07 +0000)
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

dali/internal/update/manager/update-manager.h
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/scene-graph-layer.cpp
dali/internal/update/nodes/scene-graph-layer.h
dali/internal/update/queue/update-message-queue.cpp

index 0d91cf3..9b51224 100644 (file)
@@ -654,7 +654,8 @@ private:
 
 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 ) );
@@ -665,6 +666,7 @@ inline void InstallRootMessage( UpdateManager& manager, Layer& root, bool system
 
 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
index f462feb..4a3ea63 100644 (file)
@@ -30,6 +30,16 @@ namespace //Unnamed namespace
 //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
 }
 
 namespace Dali
@@ -100,6 +110,11 @@ Node::Node()
 {
   mUniformMapChanged[0] = 0u;
   mUniformMapChanged[1] = 0u;
+
+#ifdef DEBUG_ENABLED
+  gNodeCount++;
+#endif
+
 }
 
 Node::~Node()
@@ -108,6 +123,10 @@ Node::~Node()
   {
     mTransformManager->RemoveTransform(mTransformId);
   }
+
+#ifdef DEBUG_ENABLED
+  gNodeCount--;
+#endif
 }
 
 void Node::OnDestroy()
index 4519171..46bb14c 100644 (file)
@@ -113,6 +113,15 @@ void Layer::ClearRenderables()
 
 } // 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
index d3ea452..f56bdd3 100644 (file)
@@ -332,6 +332,10 @@ inline void SetDepthTestDisabledMessage( EventThreadServices& eventThreadService
 
 } // namespace SceneGraph
 
+// Template specialisation for OwnerPointer<Layer>, because delete is protected
+template <>
+void OwnerPointer<Dali::Internal::SceneGraph::Layer>::Reset();
+
 } // namespace Internal
 
 } // namespace Dali
index 0e361f7..f6f7193 100644 (file)
@@ -76,7 +76,11 @@ struct MessageQueue::Impl
   ~Impl()
   {
     // Delete the current buffer
-    delete currentMessageBuffer;
+    if( currentMessageBuffer )
+    {
+      DeleteBufferContents( currentMessageBuffer );
+      delete currentMessageBuffer;
+    }
 
     // Delete the unprocessed buffers
     const MessageBufferIter processQueueEndIter = processQueue.end();