This project is read-only.

Memory leak when not manualy disposing events

Sep 27, 2010 at 6:26 PM

Hi, I've found that I have very large memory leaks when I don't manually call dispose on my events. Below you'll find two tests, one that does call dispose and one that doesn't. If you open task manager you'll notice how it eats ram. Is this as expected?

 

        [Test]
        public void HasMassiveMemoryLeak()
        {
            string correctSource =
@"__kernel void ActivateUpperToLower(
	__global float *lowerValues, 
	__global float *upperValues, 
	__global float *weights)
{
	int lower = get_global_id(0);
}";

            Cl.ErrorCode error;

            using (Cl.Program program = Cl.CreateProgramWithSource(_context, 1, new[] { correctSource }, null, out error))
            {
                error = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
                if (error != Cl.ErrorCode.Success)
                {
                    char[] buffer = new char[9000];
                    Cl.InfoBuffer infoBuffer = new Cl.InfoBuffer(new IntPtr(9000));
                    IntPtr retSize;
                    Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Log, new IntPtr(9000), infoBuffer, out retSize);
                    Assert.Fail(infoBuffer.ToString());
                }

                Assert.AreEqual(error, Cl.ErrorCode.Success);
                error = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
                Assert.AreEqual(Cl.ErrorCode.Success, error);
                Assert.AreEqual(Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Status, out error).CastTo<Cl.BuildStatus>(), Cl.BuildStatus.Success);
                Cl.Kernel kernel = Cl.CreateKernel(program, "ActivateUpperToLower", out error);
                Assert.AreEqual(Cl.ErrorCode.Success, error);

                Cl.CommandQueue commandQueue = Cl.CreateCommandQueue(_context, _device, (Cl.CommandQueueProperties)0, out error);
                float[] array = new float[10];
                Cl.Mem mem = Cl.CreateBuffer(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadWrite, (IntPtr)(sizeof(float) * array.Length), array, out error);

                for (int i = 0; i < 1000000; i++)
                {
                    Cl.Event clevent;
                    IntPtr event_handle = IntPtr.Zero;
                    error = Cl.EnqueueReadBuffer(commandQueue, mem, Cl.Bool.True, IntPtr.Zero, new IntPtr(array.Length * sizeof(float)), array, 0, null, out clevent);
                    // **************************************
                    // THIS IS WHAT CAUSES THE MEMORY LEAK!!!
                    // **************************************
                    // clevent.Dispose();
                }
            }
        }

        [Test]
        public void NoMemoryLeak()
        {
            string correctSource =
@"__kernel void ActivateUpperToLower(
	__global float *lowerValues, 
	__global float *upperValues, 
	__global float *weights)
{
	int lower = get_global_id(0);
}";

            Cl.ErrorCode error;

            using (Cl.Program program = Cl.CreateProgramWithSource(_context, 1, new[] { correctSource }, null, out error))
            {
                error = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
                if (error != Cl.ErrorCode.Success)
                {
                    char[] buffer = new char[9000];
                    Cl.InfoBuffer infoBuffer = new Cl.InfoBuffer(new IntPtr(9000));
                    IntPtr retSize;
                    Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Log, new IntPtr(9000), infoBuffer, out retSize);
                    Assert.Fail(infoBuffer.ToString());
                }

                Assert.AreEqual(error, Cl.ErrorCode.Success);
                error = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
                Assert.AreEqual(Cl.ErrorCode.Success, error);
                Assert.AreEqual(Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Status, out error).CastTo<Cl.BuildStatus>(), Cl.BuildStatus.Success);
                Cl.Kernel kernel = Cl.CreateKernel(program, "ActivateUpperToLower", out error);
                Assert.AreEqual(Cl.ErrorCode.Success, error);

                Cl.CommandQueue commandQueue = Cl.CreateCommandQueue(_context, _device, (Cl.CommandQueueProperties)0, out error);
                if (error != Cl.ErrorCode.Success)
                {
                    throw new InvalidProgramException(string.Format("Unable to CreateCommandQueue: {0}!", error));
                }

                float[] array = new float[10];
                Cl.Mem mem = Cl.CreateBuffer(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadWrite, (IntPtr)(sizeof(float) * array.Length), array, out error);

                for (int i = 0; i < 1000000; i++)
                {
                    Cl.Event clevent;
                    IntPtr event_handle = IntPtr.Zero;
                    error = Cl.EnqueueReadBuffer(commandQueue, mem, Cl.Bool.True, IntPtr.Zero, new IntPtr(array.Length * sizeof(float)), array, 0, null, out clevent);
                    // *****************************************
                    // THIS IS WHAT PREVENTS THE MEMORY LEAK!!!
                    // *****************************************
                    clevent.Dispose();
                }
                if (error != Cl.ErrorCode.Success)
                {
                    throw new InvalidOperationException("EnqueueReadBuffer failed for _weightsMem:" + error);
                }
                kernel.SetKernelArgFloat(0, mem);
            }
        }

Sep 28, 2010 at 6:59 PM

I haven't implemented finalizers on purpose, because they're bad in more ways than one (http://en.csharp-online.net/Classes,_Structs,_and_Objects%E2%80%94Finalizers). I would recommend a "using" statement that wraps any events you might need.

Hope that helps,
Ananth

Sep 28, 2010 at 7:01 PM

Yep, that explains it

With regards,

mattias

Från: ananth [mailto:notifications@codeplex.com]
Skickat: den 28 september 2010 20:00
Till: Mattias Fagerlund
Ämne: Re: Memory leak when not manualy disposing events [openclnet:228742]

From: ananth

I haven't implemented finalizers on purpose, because they're bad in more ways than one (http://en.csharp-online.net/Classes,_Structs,_and_Objects%E2%80%94Finalizers). I would recommend a "using" statement that wraps any events you might need.

Hope that helps,
Ananth

Read the full discussion online.

To add a post to this discussion, reply to this email (openclnet@discussions.codeplex.com)

To start a new discussion for this project, email openclnet@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com