[NUI][API11] Fix some memory leak codes what already fixed at API12
authorEunki Hong <eunkiki.hong@samsung.com>
Fri, 19 Jan 2024 01:28:11 +0000 (10:28 +0900)
committerEunki Hong <h.pichulia@gmail.com>
Mon, 18 Mar 2024 08:02:17 +0000 (17:02 +0900)
Let we backport some minor memory leak resolve PR what we already merged.

This PR squash 4 different patches.

---

Fix some incorrect implements when we get Texture relative items

Since now we have a unified pattern to avoid memory leak problem
between NUI and Native side handle count problem,
Let we change some mis-implementated codes relative with Texture.

(Follow PR #5892)

Add some remarks at BaseHandle class about Dispose

(Follow PR #5893)

Resolve memory leak for DisposeTest sample

There was leak issue since we don't call FreeHGlobal after AllocHGlobal.

And also, let we Dispose Renderer / Geometry / Shader / TextureSet what NUI create.
Those classes memory might give confuse when we test the memory.

(Follow PR #5895)

Call Mashal.FreeHGlobal() what we allocated

Let we free allocated heap memory by Mashal.

It might cause memory leak issue if user try to use VertexBuffer.

And also, let we also fix FrameBrokerBase implementation
that might be the guideline who want to use custom Geometry class.

(Follow PR #5902)

12 files changed:
src/Tizen.NUI.Wearable/src/public/Title.cs
src/Tizen.NUI/src/internal/Common/FrameBuffer.cs
src/Tizen.NUI/src/internal/FrameBroker/FrameBrokerBase.cs
src/Tizen.NUI/src/internal/Transition/TransitionSet.cs
src/Tizen.NUI/src/public/BaseComponents/DirectRenderingGLView.cs
src/Tizen.NUI/src/public/BaseComponents/ViewAccessibilityWrappers.cs
src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs
src/Tizen.NUI/src/public/Common/BaseHandle.cs
src/Tizen.NUI/src/public/Rendering/Renderer.cs
src/Tizen.NUI/src/public/Rendering/TextureSet.cs
src/Tizen.NUI/src/public/Rendering/VertexBuffer.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeTest.cs

index 7934030..dc86d9c 100755 (executable)
@@ -326,17 +326,24 @@ namespace Tizen.NUI.Components
             vertex3.position = new Vec2(0.5f, -0.5f);
             vertex4.position = new Vec2(0.5f, 0.5f);
 
-
             TexturedQuadVertex[] texturedQuadVertexData = new TexturedQuadVertex[4] { vertex1, vertex2, vertex3, vertex4 };
 
-            int lenght = Marshal.SizeOf(vertex1);
-            IntPtr pA = Marshal.AllocHGlobal(lenght * 4);
+            int length = Marshal.SizeOf(vertex1);
+            IntPtr pA = Marshal.AllocHGlobal(checked(length * 4));
 
-            for (int i = 0; i < 4; i++)
+            try
+            {
+                for (int i = 0; i < 4; i++)
+                {
+                    Marshal.StructureToPtr(texturedQuadVertexData[i], pA + i * length, true);
+                }
+                vertexData.SetData(pA, 4);
+            }
+            finally
             {
-                Marshal.StructureToPtr(texturedQuadVertexData[i], pA + i * lenght, true);
+                // Free AllocHGlobal memory after call PropertyBuffer.SetData()
+                Marshal.FreeHGlobal(pA);
             }
-            vertexData.SetData(pA, 4);
 
             Geometry geometry = new Geometry();
             geometry.AddVertexBuffer(vertexData);
index dc8ee22..d0efc51 100755 (executable)
@@ -66,10 +66,17 @@ namespace Tizen.NUI
 
         public Texture GetColorTexture()
         {
-            //to fix memory leak issue, match the handle count with native side.
             global::System.IntPtr cPtr = Interop.FrameBuffer.GetColorTexture(SwigCPtr);
-            Texture ret = this.GetInstanceSafely<Texture>(cPtr);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            Texture ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Texture;
+            if (ret != null)
+            {
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = new Texture(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
index 9212314..4330679 100755 (executable)
@@ -292,8 +292,15 @@ namespace Tizen.NUI
             public Vec2 position;
         };
 
-        private IntPtr RectangleDataPtr()
+        private PropertyBuffer CreateQuadPropertyBuffer()
         {
+            /* Create Property buffer */
+            PropertyValue value = new PropertyValue((int)PropertyType.Vector2);
+            PropertyMap vertexFormat = new PropertyMap();
+            vertexFormat.Add("aPosition", value);
+
+            PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
+            
             TexturedQuadVertex vertex1 = new TexturedQuadVertex();
             TexturedQuadVertex vertex2 = new TexturedQuadVertex();
             TexturedQuadVertex vertex3 = new TexturedQuadVertex();
@@ -305,33 +312,38 @@ namespace Tizen.NUI
 
             TexturedQuadVertex[] texturedQuadVertexData = new TexturedQuadVertex[4] { vertex1, vertex2, vertex3, vertex4 };
 
-            int lenght = Marshal.SizeOf(vertex1);
-            IntPtr pA = Marshal.AllocHGlobal(lenght * 4);
+            int length = Marshal.SizeOf(vertex1);
+            IntPtr pA = Marshal.AllocHGlobal(checked(length * 4));
 
-            for (int i = 0; i < 4; i++)
+            try
             {
-                Marshal.StructureToPtr(texturedQuadVertexData[i], pA + i * lenght, true);
+                for (int i = 0; i < 4; i++)
+                {
+                    Marshal.StructureToPtr(texturedQuadVertexData[i], pA + i * length, true);
+                }
+
+                vertexBuffer.SetData(pA, 4);
+            }
+            finally
+            {
+                // Free AllocHGlobal memory after call PropertyBuffer.SetData()
+                Marshal.FreeHGlobal(pA);
             }
 
-            return pA;
+            value.Dispose();
+            vertexFormat.Dispose();
+
+            return vertexBuffer;
         }
 
         private Geometry CreateQuadGeometry()
         {
-            /* Create Property buffer */
-            PropertyValue value = new PropertyValue((int)PropertyType.Vector2);
-            PropertyMap vertexFormat = new PropertyMap();
-            vertexFormat.Add("aPosition", value);
-
-            PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
-            vertexBuffer.SetData(RectangleDataPtr(), 4);
+            PropertyBuffer vertexBuffer = CreateQuadPropertyBuffer();
 
             Geometry geometry = new Geometry();
             geometry.AddVertexBuffer(vertexBuffer);
             geometry.SetType(Geometry.Type.TRIANGLE_STRIP);
 
-            value.Dispose();
-            vertexFormat.Dispose();
             vertexBuffer.Dispose();
 
             return geometry;
index 0750567..aec4a56 100755 (executable)
@@ -118,22 +118,17 @@ namespace Tizen.NUI
 
         public TransitionItemBase GetTransitionAt(uint index)
         {
-            //to fix memory leak issue, match the handle count with native side.
             IntPtr cPtr = Interop.TransitionSet.GetTransitionAt(SwigCPtr, index);
-            HandleRef CPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
-            TransitionItemBase ret = Registry.GetManagedBaseHandleFromNativePtr(CPtr.Handle) as TransitionItemBase;
-            if (cPtr != IntPtr.Zero && ret == null)
+            TransitionItemBase ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as TransitionItemBase;
+            if (ret != null)
             {
-                ret = new TransitionItemBase(cPtr, false);
-                if (NDalicPINVOKE.SWIGPendingException.Pending)
-                    throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-                return ret;
+                Interop.BaseHandle.DeleteBaseHandle(new HandleRef(this, cPtr));
             }
-            Interop.BaseHandle.DeleteBaseHandle(CPtr);
-            CPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
-
-            if (NDalicPINVOKE.SWIGPendingException.Pending)
-                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            else
+            {
+                ret = new TransitionItemBase(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
index 14876ef..2dafb54 100644 (file)
@@ -241,18 +241,24 @@ namespace Tizen.NUI.BaseComponents
                 if (textures != null)
                 {
                     int count = textures.Count;
-                    if (count > 0)
+                    int intptrBytes = checked(Marshal.SizeOf(typeof(IntPtr)) * count);
+                    if (intptrBytes > 0)
                     {
                         IntPtr[] texturesArray = new IntPtr[count];
                         for (int i = 0; i < count; i++)
                         {
                             texturesArray[i] = HandleRef.ToIntPtr(Texture.getCPtr(textures[i]));
                         }
-                        IntPtr unmanagedPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * count);
-                        Marshal.Copy(texturesArray, 0, unmanagedPointer, count);
-
-                        Interop.GLView.GlViewBindTextureResources(SwigCPtr, unmanagedPointer, count);
-                        Marshal.FreeHGlobal(unmanagedPointer);
+                        IntPtr unmanagedPointer = Marshal.AllocHGlobal(intptrBytes);
+                        try
+                        {
+                            Marshal.Copy(texturesArray, 0, unmanagedPointer, texturesArray.Length);
+                            Interop.GLView.GlViewBindTextureResources(SwigCPtr, unmanagedPointer, texturesArray.Length);
+                        }
+                        finally
+                        {
+                            Marshal.FreeHGlobal(unmanagedPointer);
+                        }
                     }
                 }
             }
index 6b48d1c..817aea5 100644 (file)
@@ -45,6 +45,9 @@ namespace Tizen.NUI.BaseComponents
 
             Marshal.StructureToPtr(ad, ptr, false);
             Interop.ControlDevel.DaliAccessibilitySetAccessibilityDelegate(ptr, Convert.ToUInt32(size));
+
+            // Do not free AllocHGlobal memory, for performance. It will be used for native side very frequencly.
+            // Note that Marshal.AllocHGlobal memory will be freed after process terminated.
         }
 
         private static View GetViewFromRefObject(IntPtr refObjectPtr)
index ce45a7c..5da4b3b 100755 (executable)
@@ -613,22 +613,17 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 3 </since_tizen>
         public Renderer GetRendererAt(uint index)
         {
-            //to fix memory leak issue, match the handle count with native side.
             IntPtr cPtr = Interop.Actor.GetRendererAt(SwigCPtr, index);
-            HandleRef CPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
-            Renderer ret = Registry.GetManagedBaseHandleFromNativePtr(CPtr.Handle) as Renderer;
-            if (cPtr != IntPtr.Zero && ret == null)
+            Renderer ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Renderer;
+            if (ret != null)
             {
-                ret = new Renderer(cPtr, false);
-                if (NDalicPINVOKE.SWIGPendingException.Pending)
-                    throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-                return ret;
+                Interop.BaseHandle.DeleteBaseHandle(new HandleRef(this, cPtr));
             }
-            Interop.BaseHandle.DeleteBaseHandle(CPtr);
-            CPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
-
-            if (NDalicPINVOKE.SWIGPendingException.Pending)
-                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            else
+            {
+                ret = new Renderer(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
index 1bff524..9ffb856 100755 (executable)
@@ -25,6 +25,11 @@ namespace Tizen.NUI
     /// <summary>
     /// BaseHandle is a handle to an internal Dali resource.
     /// </summary>
+    /// <remarks>
+    /// Internal Dali resources with BaseHandle has reference count internally.<br/>
+    /// And Dali resources will release the object only if reference count become zero.<br/>
+    /// It mean, even we call <see cref="Dispose()"/>, the reousrce will not be released if some native has reference count.
+    /// </remarks>
     /// <since_tizen> 3 </since_tizen>
     public class BaseHandle : Element, global::System.IDisposable
     {
@@ -335,6 +340,10 @@ namespace Tizen.NUI
         /// <summary>
         /// Dispose.
         /// </summary>
+        /// <remarks>
+        /// This method release only C# side objects. If someone hold BaseHandle at Native side<br/>
+        /// the object will not be removed until native side reset the handle.
+        /// </remarks>
         /// <since_tizen> 3 </since_tizen>
         public void Dispose()
         {
index 77d5213..fbc4b3f 100755 (executable)
@@ -766,20 +766,17 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         public TextureSet GetTextures()
         {
-            //to fix memory leak issue, match the handle count with native side.
-            System.IntPtr cPtr = Interop.Renderer.GetTextures(SwigCPtr);
-            HandleRef CPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
-            TextureSet ret = Registry.GetManagedBaseHandleFromNativePtr(CPtr.Handle) as TextureSet;
-            if (cPtr != IntPtr.Zero && ret == null)
+            global::System.IntPtr cPtr = Interop.Renderer.GetTextures(SwigCPtr);
+            TextureSet ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as TextureSet;
+            if (ret != null)
             {
-                ret = new TextureSet(cPtr, false);
-                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-                return ret;
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
             }
-            Interop.BaseHandle.DeleteBaseHandle(CPtr);
-            CPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
-
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            else
+            {
+                ret = new TextureSet(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
index 3ad3302..664aa3a 100755 (executable)
@@ -60,20 +60,17 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         public Texture GetTexture(uint index)
         {
-            //to fix memory leak issue, match the handle count with native side.
-            System.IntPtr cPtr = Interop.TextureSet.GetTexture(SwigCPtr, index);
-            HandleRef CPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
-            Texture ret = Registry.GetManagedBaseHandleFromNativePtr(CPtr.Handle) as Texture;
-            if (cPtr != System.IntPtr.Zero && ret == null)
+            global::System.IntPtr cPtr = Interop.TextureSet.GetTexture(SwigCPtr, index);
+            Texture ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Texture;
+            if (ret != null)
             {
-                ret = new Texture(cPtr, false);
-                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-                return ret;
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
             }
-            Interop.BaseHandle.DeleteBaseHandle(CPtr);
-            CPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
-
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            else
+            {
+                ret = new Texture(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
@@ -97,10 +94,17 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         public Sampler GetSampler(uint index)
         {
-            //to fix memory leak issue, match the handle count with native side.
-            System.IntPtr cPtr = Interop.TextureSet.GetSampler(SwigCPtr, index);
-            Sampler ret = this.GetInstanceSafely<Sampler>(cPtr);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            global::System.IntPtr cPtr = Interop.TextureSet.GetSampler(SwigCPtr, index);
+            Sampler ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Sampler;
+            if (ret != null)
+            {
+                Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+            }
+            else
+            {
+                ret = new Sampler(cPtr, true);
+            }
+            NDalicPINVOKE.ThrowExceptionIfExists();
             return ret;
         }
 
index 8c4fd0d..25dd5d2 100755 (executable)
@@ -63,12 +63,21 @@ namespace Tizen.NUI
             int structSize = Marshal.SizeOf<VertexType>();
             global::System.IntPtr buffer = Marshal.AllocHGlobal(checked(structSize * vertices.Length));
 
-            for (int i = 0; i < vertices.Length; i++)
+            try
             {
-                Marshal.StructureToPtr(vertices[i], buffer + i * structSize, true);
+                for (int i = 0; i < vertices.Length; i++)
+                {
+                    Marshal.StructureToPtr(vertices[i], buffer + i * structSize, true);
+                }
+
+                Interop.VertexBuffer.SetData(SwigCPtr, buffer, (uint)vertices.Length);
+            }
+            finally
+            {
+                // Free AllocHGlobal memory after call Interop.VertexBuffer.SetData()
+                Marshal.FreeHGlobal(buffer);
             }
 
-            Interop.VertexBuffer.SetData(SwigCPtr, buffer, (uint)vertices.Length);
             if (NDalicPINVOKE.SWIGPendingException.Pending)
                 throw NDalicPINVOKE.SWIGPendingException.Retrieve();
         }
index 2f24a7c..616adb0 100644 (file)
@@ -100,7 +100,7 @@ namespace Tizen.NUI.Samples
 
         // Copy from dali-toolkit/internal/visuals/primitive/primitive-visual.cpp
         // NOTE. I add one more slices for texture coordinate
-        private global::System.IntPtr SphereVertexDataPtr()
+        private TexturedQuadVertex[] SphereVertexData()
         {
             TexturedQuadVertex[] vertices = new TexturedQuadVertex[SPHERE_VERTEX_NUMBER];
 
@@ -148,15 +148,7 @@ namespace Tizen.NUI.Samples
             }
             // Build done.
 
-            int length = Marshal.SizeOf(vertices[0]);
-            global::System.IntPtr pA = Marshal.AllocHGlobal(length * SPHERE_VERTEX_NUMBER);
-
-            for (int i = 0; i < SPHERE_VERTEX_NUMBER; i++)
-            {
-                Marshal.StructureToPtr(vertices[i], pA + i * length, true);
-            }
-
-            return pA;
+            return vertices;
         }
 
         private ushort[] SphereIndexData()
@@ -212,7 +204,6 @@ namespace Tizen.NUI.Samples
         const int SPHERE_VERTEX_NUMBER = (SPHERE_SLICES + 1) * (SPHERE_STACKS - 1) + 2;
         const int SPHERE_INDEX_NUMBER = 6 * SPHERE_SLICES * (SPHERE_STACKS - 1);
 
-
         private const int AutoDisposedObjectCount = 10;
         private const int ManualDisposedObjectCount = 10;
         private const int RecuvelyDisposedObjectCount = 10;
@@ -223,8 +214,11 @@ namespace Tizen.NUI.Samples
         private string resource;
         private List<Custom3DView> views;
         private List<Custom3DView> depthViews; // List of tree-formed views. 0 indexes view is root.
+        private List<Renderer> renderers;
         private Animation rotateAnimation;
 
+        private Dictionary<string, Texture> textureDictionary = new();
+
         public void Activate()
         {
             win = NUIApplication.GetDefaultWindow();
@@ -241,6 +235,7 @@ namespace Tizen.NUI.Samples
 
             views = new List<Custom3DView>();
             depthViews = new List<Custom3DView>();
+            renderers = new List<Renderer>();
             rotateAnimation = new Animation(1500); //1.5s
 
             AddManyViews();
@@ -249,7 +244,6 @@ namespace Tizen.NUI.Samples
             timer = new Timer(3000); //3s
             timer.Tick += OnTimerTick;
             timer.Start();
-
         }
 
         private bool OnTimerTick(object source, Timer.TickEventArgs e)
@@ -273,13 +267,31 @@ namespace Tizen.NUI.Samples
 
         private Geometry GenerateGeometry()
         {
-            PropertyMap vertexFormat = new PropertyMap();
+            using PropertyMap vertexFormat = new PropertyMap();
             vertexFormat.Add("aPosition", new PropertyValue((int)PropertyType.Vector3));
             vertexFormat.Add("aNormal", new PropertyValue((int)PropertyType.Vector3));
             vertexFormat.Add("aTexCoord", new PropertyValue((int)PropertyType.Vector2));
-            PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
+            using PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
 
-            vertexBuffer.SetData(SphereVertexDataPtr(), SPHERE_VERTEX_NUMBER);
+            TexturedQuadVertex[] vertices = SphereVertexData();
+
+            int length = Marshal.SizeOf(vertices[0]);
+            global::System.IntPtr pA = Marshal.AllocHGlobal(checked(length * SPHERE_VERTEX_NUMBER));
+
+            try
+            {
+                for (int i = 0; i < SPHERE_VERTEX_NUMBER; i++)
+                {
+                    Marshal.StructureToPtr(vertices[i], pA + i * length, true);
+                }
+
+                vertexBuffer.SetData(pA, SPHERE_VERTEX_NUMBER);
+            }
+            finally
+            {
+                // We can free raw data after SetData call finished.
+                Marshal.FreeHGlobal(pA);
+            }
 
             ushort[] indexBuffer = SphereIndexData();
 
@@ -287,9 +299,51 @@ namespace Tizen.NUI.Samples
             geometry.AddVertexBuffer(vertexBuffer);
             geometry.SetIndexBuffer(indexBuffer, SPHERE_INDEX_NUMBER);
             geometry.SetType(Geometry.Type.TRIANGLES);
+
             return geometry;
         }
 
+        private Shader GenerateShader()
+        {
+            Shader shader = new Shader(VERTEX_SHADER, FRAGMENT_SHADER);
+            return shader;
+        }
+
+        private Renderer GenerateRenderer(string textureUrl)
+        {
+            Texture texture;
+            if (!textureDictionary.TryGetValue(textureUrl, out texture))
+            {
+                // Let we load image only 1 times per each objects
+                using PixelData pixelData = PixelBuffer.Convert(ImageLoader.LoadImageFromFile(
+                    textureUrl,
+                    new Size2D(),
+                    FittingModeType.ScaleToFill
+                ));
+
+                texture = new Texture(
+                    TextureType.TEXTURE_2D,
+                    pixelData.GetPixelFormat(),
+                    pixelData.GetWidth(),
+                    pixelData.GetHeight()
+                );
+                texture.Upload(pixelData);
+                if (!textureDictionary.TryAdd(textureUrl, texture))
+                {
+                    Tizen.Log.Error("NUI", "Something wrong when we try to add Texture into dictionary\n");
+                }
+            }
+            TextureSet textureSet = new TextureSet();
+            textureSet.SetTexture(0u, texture);
+
+            Renderer renderer = new Renderer(GenerateGeometry(), GenerateShader());
+            renderer.SetTextures(textureSet);
+
+            renderers.Add(renderer);
+
+            return renderer;
+        }
+
         private void AddManyViews()
         {
             Random rand = new Random();
@@ -308,24 +362,7 @@ namespace Tizen.NUI.Samples
                     Name = "Auto_" + i.ToString(),
                 };
                 root.Add(view);
-
-                PixelData pixelData = PixelBuffer.Convert(ImageLoader.LoadImageFromFile(
-                    resource + "/images/PopupTest/circle.jpg",
-                    new Size2D(),
-                    FittingModeType.ScaleToFill
-                ));
-                Texture texture = new Texture(
-                    TextureType.TEXTURE_2D,
-                    pixelData.GetPixelFormat(),
-                    pixelData.GetWidth(),
-                    pixelData.GetHeight()
-                );
-                texture.Upload(pixelData);
-                TextureSet textureSet = new TextureSet();
-                textureSet.SetTexture(0u, texture);
-                Renderer renderer = new Renderer(GenerateGeometry(), new Shader(VERTEX_SHADER, FRAGMENT_SHADER));
-                renderer.SetTextures(textureSet);
-                view.AddRenderer(renderer);
+                view.AddRenderer(GenerateRenderer(resource + "/images/PopupTest/circle.jpg"));
 
                 rotateAnimation.AnimateBy(view, "Orientation", new Rotation(new Radian(new Degree(360.0f)), Vector3.YAxis));
             }
@@ -346,23 +383,7 @@ namespace Tizen.NUI.Samples
                 root.Add(view);
                 views.Add(view);
 
-                PixelData pixelData = PixelBuffer.Convert(ImageLoader.LoadImageFromFile(
-                    resource + "/images/PaletteTest/red2.jpg",
-                    new Size2D(),
-                    FittingModeType.ScaleToFill
-                ));
-                Texture texture = new Texture(
-                    TextureType.TEXTURE_2D,
-                    pixelData.GetPixelFormat(),
-                    pixelData.GetWidth(),
-                    pixelData.GetHeight()
-                );
-                texture.Upload(pixelData);
-                TextureSet textureSet = new TextureSet();
-                textureSet.SetTexture(0u, texture);
-                Renderer renderer = new Renderer(GenerateGeometry(), new Shader(VERTEX_SHADER, FRAGMENT_SHADER));
-                renderer.SetTextures(textureSet);
-                view.AddRenderer(renderer);
+                view.AddRenderer(GenerateRenderer(resource + "/images/PaletteTest/red2.jpg"));
 
                 rotateAnimation.AnimateBy(view, "Orientation", new Rotation(new Radian(new Degree(-360.0f)), Vector3.YAxis));
             }
@@ -399,23 +420,7 @@ namespace Tizen.NUI.Samples
                 }
                 depthViews.Add(view);
 
-                PixelData pixelData = PixelBuffer.Convert(ImageLoader.LoadImageFromFile(
-                    resource + "/images/PaletteTest/rock.jpg",
-                    new Size2D(),
-                    FittingModeType.ScaleToFill
-                ));
-                Texture texture = new Texture(
-                    TextureType.TEXTURE_2D,
-                    pixelData.GetPixelFormat(),
-                    pixelData.GetWidth(),
-                    pixelData.GetHeight()
-                );
-                texture.Upload(pixelData);
-                TextureSet textureSet = new TextureSet();
-                textureSet.SetTexture(0u, texture);
-                Renderer renderer = new Renderer(GenerateGeometry(), new Shader(VERTEX_SHADER, FRAGMENT_SHADER));
-                renderer.SetTextures(textureSet);
-                view.AddRenderer(renderer);
+                view.AddRenderer(GenerateRenderer(resource + "/images/PaletteTest/rock.jpg"));
 
                 //rotateAnimation.AnimateBy(view, "Orientation", new Rotation(new Radian(new Degree(360.0f)), Vector3.ZAxis));
             }
@@ -429,19 +434,26 @@ namespace Tizen.NUI.Samples
             {
                 root.Remove(root.GetChildAt((uint)i));
             }
-            foreach(var view in views)
+            foreach (var view in views)
             {
-                var renderer = view.GetRendererAt(0);
-                renderer.Dispose();
-                view.Dispose();
+                view?.Dispose();
             }
-            if(depthViews?.Count > 0)
+            foreach (var renderer in renderers)
             {
-                depthViews[0].DisposeRecursively();
+                renderer?.GetGeometry()?.Dispose();
+                renderer?.GetShader()?.Dispose();
+                renderer?.GetTextures()?.Dispose();
+                renderer?.Dispose();
+            }
+            if (depthViews?.Count > 0)
+            {
+                depthViews[0]?.DisposeRecursively();
             }
 
             views.Clear();
             depthViews.Clear();
+            renderers.Clear();
+
             rotateAnimation.Clear();
         }
 
@@ -460,6 +472,8 @@ namespace Tizen.NUI.Samples
             root.Unparent();
             root.Dispose();
 
+            textureDictionary.Clear();
+
             // Revert default layer behavior as LayerUI
             win.GetDefaultLayer().Behavior = Layer.LayerBehavior.LayerUI;
         }