1

I have this method:

public static string XmlSerialize<T>(T data)
{
    string result;
    using (StringWriter stringWriter = new StringWriter())
    {
        XmlWriterSettings settings = new XmlWriterSettings
        {
            Encoding = Encoding.UTF8,
            OmitXmlDeclaration = true,
        };
        using (XmlWriter writer = XmlWriter.Create(stringWriter, settings))
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            XmlSerializer serializer = XmlSerializer.FromTypes(new[] { typeof(T) })[0];
            serializer.Serialize(writer, data, ns);
        }
        result = stringWriter.ToString();
    }

    return result;
}

This is simple method to serialize object into xml. But this method have memory leak, and I haven't idea where is it.

Can anyone help me find it?

TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69
Lasoty
  • 115
  • 2
  • 12
  • 3
    Why have you decided this method has memory leak? What makes you think so? – Andrey Korneyev Dec 01 '16 at 12:26
  • 1
    Can´t see anything here that can´t be handled by GC when leaving the method. So why do you think there *is* a memory-leak? – MakePeaceGreatAgain Dec 01 '16 at 12:31
  • Because when I used this method to serialize one object 10 000 times, memory used by program up to 100MB (from 10MB). – Lasoty Dec 01 '16 at 12:35
  • That doesn´t mean it´s not released. Garbage collection is undeterminstic, you can´t say when it´s finished andf thus when your memory is relased, only that it happens. Anyway: how did you determine it uses 100MB? Don´t trust TaskManager too much when it comes to Memory. – MakePeaceGreatAgain Dec 01 '16 at 12:37
  • Because you keep that string in memory. It is obvious that memory will grow by doing that. – mrogal.ski Dec 01 '16 at 12:37
  • 1
    code looks fine to me, but you can read more here: http://stackoverflow.com/questions/7524903/should-i-call-close-or-dispose-for-stream-objects – Thomas Koelle Dec 01 '16 at 12:40
  • Program used 650MB memory after night. If GC works correctly in this case this shouldn't happen. – Lasoty Dec 01 '16 at 12:49
  • As you said, you serialize 10 000 objects (same or not - doesnt matter), but the most important thing is that you're serializing this into a string (which is held in memory) and then you just return this string (we still dont know where). So my guess is that you have some list in which you keep those serialized objects. – mrogal.ski Dec 01 '16 at 12:59
  • This is the context of the use this method: `using (StatusResp status = new StatusResp()) { status.Data = new StatusData(); status.Data.Power_Available = true; status.Data.CardChannelActive = true; status.Data.CashChannelActive = true; UdpManager.Instance.Send(Utilities.XmlSerialize(status)); }` – Lasoty Dec 01 '16 at 13:11
  • When I use `UdpManager.Instance.Send($"Status{status.Data.CashChannelActive}{status.Data.CardChannelActive}{status.Data.MifareActive}{status.Data.Power_Available}");` instead of `UdpManager.Instance.Send(Utilities.XmlSerialize(status)); ` the memory does not grow. – Lasoty Dec 01 '16 at 13:15
  • Okay so based on [ReferenceSource](https://referencesource.microsoft.com) `StringWriter` uses `StringBuilder` to produce string result but it does not finalize `StringBuilder`. And **MAYBE** if you're calling this function too fast or too often the `StringBuilder` inside is just held down in memory. [check this source](https://referencesource.microsoft.com/#mscorlib/system/io/stringwriter.cs,47872c8709d73365) – mrogal.ski Dec 01 '16 at 14:26

2 Answers2

0

The problem is with a leak in XMLSerializer and it is an official behavior by design.

MS Documenation on XMLSerializer

Dynamically Generated Assemblies

To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:

XmlSerializer.XmlSerializer(Type)    
XmlSerializer.XmlSerializer(Type, String)

If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example

And read more here on SO for XmlSerializer.FromTypes:

XmlSerializer.FromTypes producing memory leaks?

Community
  • 1
  • 1
hB0
  • 1,977
  • 1
  • 27
  • 33
-1

You should release the resources from the memory by using Dispose() method because C# garbage collector doesn't do that to any object has Dispose() method.

public static string XmlSerialize<T>(T data)
{
string result;
using (StringWriter stringWriter = new StringWriter())
{
    XmlWriterSettings settings = new XmlWriterSettings
    {
        Encoding = Encoding.UTF8,
        OmitXmlDeclaration = true,
    };
    using (XmlWriter writer = XmlWriter.Create(stringWriter, settings))
    {
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        XmlSerializer serializer = XmlSerializer.FromTypes(new[] { typeof(T) })[0];
        serializer.Serialize(writer, data, ns);
        if (writer != null)
            writer.Dispose();
    }
    result = stringWriter.ToString();
    if (stringWriter != null)
        stringWriter.Dispose();
}

return result;
}
M.Sarmini
  • 70
  • 3