I had noticed memory leak in my application and tried to find it out. I don't know good and free memory leaking discovering techniques (any suggestions?) so I made it simple - inserted memory usage prints (with and without GC) and then dig deeper where biggest leak was. Fixable I had fixed but some I can not because they are inside packages. Like this very simplified one
using System;
using System.Threading;
using DocumentFormat.OpenXml.Packaging;
namespace WorkTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("0) " + System.GC.GetTotalMemory(true).ToString("000,000,000", Thread.CurrentThread.CurrentCulture));
Console.WriteLine("Start");
Console.WriteLine("1) " + System.GC.GetTotalMemory(true).ToString("000,000,000", Thread.CurrentThread.CurrentCulture));
using (WordprocessingDocument wordPackage = WordprocessingDocument.Open(@"c:\tmp\a.docx", true))
{
// This is Open XML Format SDK 2.5 - v4.0.30319
// It does nothing within this particular block/example
}
Console.WriteLine("2) " + System.GC.GetTotalMemory(true).ToString("000,000,000", Thread.CurrentThread.CurrentCulture));
Console.WriteLine("End");
Console.WriteLine("3) " + System.GC.GetTotalMemory(true).ToString("000,000,000", Thread.CurrentThread.CurrentCulture));
}
}
}
usually it produces something like
0) 000,215,984
Start
1) 000,218,528
2) 000,325,472
End
3) 000,325,472
To start with small leak - step 0-1 is simple output. It doesn't eat a lot. Only 3K but it still something. Step 2-3 is the same but it doesn't eat anything. OK. I agree. Some IO packages may need some memory. Not good but understandable.
Second one - step 1-2 is not such understandable. "Using" and even separate block {} should totally clean after themselves. And they don't. Even worse. This example is simplified. In reality every time when I execute this code within my methods memory is gone. In this one example it is 90K. After 100 documents it is 9Mb.
With described methodology I also found few places in my app when invoking GC consumes and doesn't return memory. Every time GC is called the only result that 4K memory is gone. Unfortunately I cannot reproduce it in simple example.
So far I had found only one solution - when memory became critical I restart my application. Not good solution but I can't find better one.