2

How to fix memory leaks when sorting generic lists in .NET?

private void ManageXmlIndex(XmlDocument xmlDocIndicatorIndex)
{
    indexList = repoManager.ParseIndex(xmlDocIndicatorIndex);
    indexList.Sort((x, y) => y.Created.CompareTo(x.Created));
    view.UpdateIndex(indexList);
}

enter image description here

enter image description here

enter image description here

The same happens when I'm using linq OrderBy.

Is custom comparing function can solve the problem?

The bug happens due to the List.Sort. When I comment out the Sort line, the bug disappears.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Miroslav Popov
  • 3,294
  • 4
  • 32
  • 55

2 Answers2

2

What you're seeing is not a memory leak. It's simply the way the compiler is caching your Comparison<IndicatorPropReport> as a static delegate at the call site, thus saving you the need to create an instance of it for each invocation.

If you look at this simplified example:

var ints = new List<int> { 3, 2, 1, 8, 5 };
ints.Sort((x, y) => x.CompareTo(y));

And look at what the compiler generates using an .NET decompiler:

[CompilerGenerated]
private static Comparison<int> CS$<>9__CachedAnonymousMethodDelegate2;

public static void Main(string[] args)
{
    List<int> ints = new List<int> { 3,2,1,8,5 };
    List<int> arg_51_0 = ints;

    if (Program.CS$<>9__CachedAnonymousMethodDelegate2 == null)
    {
        Program.CS$<>9__CachedAnonymousMethodDelegate2 = 
                new Comparison<int>(Program.<Main>b__1);
    }
    arg_51_0.Sort(Program.CS$<>9__CachedAnonymousMethodDelegate2);
}

[CompilerGenerated]
private static int <Main>b__1(int x, int y)
{
    return x.CompareTo(y);
}

You see that the Comparsion<int> was cached as a static delegate. The same behavior is what happens in your method call.

Note this behavior is pre Roslyn. Roslyn changes the way delegates are cached by creating a display class instead of the static delegate, even when there's no captured variables.

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • I supposed that this is the case, however, I hoped to find a solution to release it after the method/class is not needed anymore. Does it hold the whole containing class in the memory or only the delegate? – Miroslav Popov Jul 27 '15 at 10:52
  • 1
    @MiroslavPopov The class isn't kept in memory. It will be eligible for collection. – Yuval Itzchakov Jul 27 '15 at 11:01
1

I've found an answer from Microsoft support:

List<T> creates an empty array of T in its static constructor. The array is stored in a static field of List<T> so it will be alive until the AppDomain dies. So, not a memory leak.

Source: https://social.msdn.microsoft.com/forums/vstudio/en-US/dee3c1ee-fb63-43f1-88be-413136afe3ed/memory-leak-in-generic-collection

I hope that support your question.

DeJaVo
  • 3,091
  • 2
  • 17
  • 32