1

Closed

Memory leak

description

I think, there is a memory leak when I use FileSvgReader.Read method.

I have downloaded the SharpVectors converter application, and I have used the normal file converter.
The application takes ~30Mb-es after start. My svg file is about 300kb and when I click the "convert" button, the memory usage starts to increase.
When it is ready the application memory usage is ~60Mb (!!!) and do not decrease.

I have tried it with a 11Mb svg file, and the memory usage is ~700Mb after the successful convert.

It is the same situation in my applicaion which uses only the FileSvgReader.Read method.

Please check this situation!

Thank you!
Best Reagards,
Gergely

file attachments

Closed Oct 14, 2016 at 2:47 PM by SelormeyPaul
Simple memory management will resolve the issue.

comments

Spuriga wrote Jul 8, 2015 at 11:46 AM

Hello!

Could you help me, when this problem will be checked?

Thanks in advance!

SelormeyPaul wrote Jul 9, 2015 at 3:37 PM

For a library, there is little to do. If you finish with the conversion in your application, try the following to force the clean by the .NET runtime:
     GC.Collect();
     GC.WaitForPendingFinalizers();
     GC.Collect();

wrote Jul 13, 2015 at 8:33 AM

Spuriga wrote Jul 13, 2015 at 8:33 AM

Hello!

I have tried it, but not success! :(

When my code is starting it use 3Mb-s of memory, and when it is finished it use 45Mb-s. I have tried it in a cycle, doing the same 10 times, and the memory increased to 450Mb-s.

In the attachement, you can find the "Csongrad_megye.svg" file. Of course I have many map file with the same situation, not this is the only one.
static void Main(string[] args)
{
    byte[] svgByteArray = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Csongrad_megye.svg"));

    DrawingGroup dg;
    using (var stream = new MemoryStream(svgByteArray))
    {
        using (FileSvgReader fr = new FileSvgReader(null))
        {
            dg = fr.Read(stream);
        }
    }

    dg = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    Console.WriteLine("Ready!");
    Console.ReadLine();
}

SelormeyPaul wrote Jul 13, 2015 at 11:29 AM

Without testing, I could see the code you submitted is useless. How are you expecting the svgByteArray you created to go away? Why do you even need the byte array if you can directly read the file?
static void Main(string[] args)
{
    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Csongrad_megye.svg");

    DrawingGroup dg;
    using (FileSvgReader fr = new FileSvgReader(null))
    {
       dg = fr.Read(filePath);
    }

    dg = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    Console.WriteLine("Ready!");
    Console.ReadLine();
}

Spuriga wrote Jul 13, 2015 at 12:18 PM

In my application the file comes out from a WCF channel in byte array. But ok, there is no problem, with your code the situation is the same. :(

SelormeyPaul wrote Jul 16, 2015 at 6:24 PM

Hello,
There is no memory leak and nothing to fix. You simply do not control .NET memory management and that will not change. If you want a C/C++ release of memory, the closest you can get is run your conversions in a separate domain and if you done, you release the domain to release the resources associated with that domain.

NOTE: I am, therefore, closing this issue.
using System;
using System.Windows.Media;
using System.IO;
using SharpVectors.Converters;
using System.Reflection;

namespace TestConsole
{
    class Program
    {
        // Because this class is derived from MarshalByRefObject, a proxy  
        // to a MarshalByRefSvgConverter object can be returned across an AppDomain  
        // boundary. 
        public sealed class MarshalByRefSvgConverter : MarshalByRefObject
        {
            //  Call this method via a proxy. 
            public void RunTest(string filePath)
            {
                DrawingGroup dg;
                using (FileSvgReader fr = new FileSvgReader(null))
                {
                    dg = fr.Read(filePath);
                }

                dg = null;

                Console.WriteLine("Stage 2: " + GC.GetTotalMemory(true));
            }
        }


        private static void RunTest(String filePath)
        {
            DrawingGroup dg;
            using (FileSvgReader fr = new FileSvgReader(null))
            {
                dg = fr.Read(filePath);
            }         
            dg = null;

            Console.WriteLine("Stage 2: " + GC.GetTotalMemory(true));

            GC.Collect(0, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            GC.Collect(0, GCCollectionMode.Forced);
        }

        static void Main(string[] args)
        {
            String filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Csongrad_megye.svg");
            Console.WriteLine("Stage 1: " + GC.GetTotalMemory(true));

            // Program.RunTest(filePath);

            // Construct and initialize settings for a second AppDomain.
            AppDomainSetup domainSetup = new AppDomainSetup();
            domainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

            domainSetup.DisallowBindingRedirects = false;
            domainSetup.DisallowCodeDownload = true;
            domainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

            // Create the second AppDomain.
            AppDomain svgDomain = AppDomain.CreateDomain("SVG-Converter", null, domainSetup);

            // Get and display the full name of the EXE assembly. 
            string exeAssembly = Assembly.GetEntryAssembly().FullName;
            // Create an instance of MarshalByRefSvgConverter in the second AppDomain.  
            // A proxy to the object is returned.
            MarshalByRefSvgConverter svgProxy = (MarshalByRefSvgConverter)svgDomain.CreateInstanceAndUnwrap(
                    exeAssembly, typeof(MarshalByRefSvgConverter).FullName);

            // Call a method on the object via the proxy, passing the filename
            for (int i = 0; i < 10; i++)
            {
                svgProxy.RunTest(filePath);
            } 

            // Unload the second AppDomain. This deletes its object and  
            // invalidates the proxy object.
            AppDomain.Unload(svgDomain);

            Console.WriteLine("Stage 3: " + GC.GetTotalMemory(true));

            Console.WriteLine("Ready!");
            Console.ReadLine();
        }
    }
}

Spuriga wrote Jul 20, 2015 at 11:14 AM

Thanks, it work preatty well!

wrote Oct 14, 2016 at 2:47 PM