2

I'm attempting a simple test using dotMemory. I would expect the following test would pass:

[Test]
public void MemoryStream_is_disposed()
{
    using (var stream = new MemoryStream()) { }
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    dotMemory.Check(memory => memory.GetObjects(where => where.Type.Is<MemoryStream>()).ObjectsCount.Should().Be(0));
}

But it doesn't!

enter image description here

Why, and what do I need to do to get a passing test?

This is probably why I have memory leaks in my code.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
ket
  • 728
  • 7
  • 22
  • 1
    You need to check the count before, during and after. While your code is running, other code you're dependent on, may be using MemoryStream for countless other purposes. – jwdonahue Feb 29 '20 at 19:44
  • 2
    Running in release (instead of debug) should do that. – Alexei Levenkov Feb 29 '20 at 20:16
  • 1
    Disposed and eligible for garbage collection mean two different things. In particular, your stream is eligible for garbage collection not because it has been disposed, but because you have no outstanding references to that object at the point you call `GC.Collect`. But, as @alexeilevenkov points out, the Debug version of the GC is not as aggressive during the *Mark* phase, holding references alive while a reference is within function scope (allowing you to inspect the `stream` reference until the function ends). *Eligible for GC* means that, the GC decides when things are collected – Flydog57 Feb 29 '20 at 20:36
  • Thanks to all of you - there was one MemoryStream already in use, and release mode had to be used to ensure proper garbage collection of the newly constructed MemoryStream. I was completely unaware of the debug behavior, but it makes total sense. Feel free to upgrade your comment(s) to an answer if one of you is interested in doing so (otherwise I'll do it in maybe a day or so). Thanks! – ket Feb 29 '20 at 20:40
  • 1
    The answer to your question is here https://stackoverflow.com/a/59570995/779822 – Ed Pavlov Feb 29 '20 at 21:58
  • @Ed.ward Handy, thank you! – ket Feb 29 '20 at 22:00

1 Answers1

2

Disposed and eligible for garbage collection mean two different things. In particular, your stream is eligible for garbage collection not because it has been disposed, but because you have no outstanding references to that object at the point you call GC.Collect.

But, as @alexeilevenkov points out, the Debug version of the GC is not as aggressive during the Mark phase, holding references alive while a reference is within function scope (allowing you to inspect the stream reference until the function ends). Eligible for garbage collection means that, the object may get garbage collected. However, it's up to the GC to decide when things are actally collected.

In fact, in release mode, it's possible for an object to become eligible for collection and be collected even though a variable referring to the object is still in scope. If an object is created, assigned to a variable, and used near the top of a scope, but never used again in that scope, it's possible that the object gets collected before the variable goes out of scope.

Other than the rule that an object can't be collected until after the last active reference to that object finishes with it, you shouldn't make any assumptions about when a collection occurs.

Why do you think you have memory leaks in your code? Detecting true memory leaks in managed code is difficult

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • 2
    Another category of objects are those that are held alive for finalization. If an object has a registered finalizer, neither it nor any objects to which it holds a direct or indirect reference will be eligible for to be collected until after the finalizer has run. – supercat Feb 29 '20 at 21:22
  • @Flydog57 I was being facetious in my comment above, but I am working with an application where the memory consumption just keeps going up and up. I am 100% aligned with you about the difficulty of finding the leak, based solely on my current experience. :) – ket Feb 29 '20 at 21:58
  • If you have a Microsoft Premier Support contract, you can open a developer support incident. It's been nearly a decade since I worked there, but you'd be surprised what those folks can figure out from a dump – Flydog57 Feb 29 '20 at 23:30