0

I am unit testing my code for memory leaks. If I call Popup.IsOpen = true, then the garbage collector does not collect the popup or its child. If I comment out Popup.IsOpen = true, the garbage collector will collect both.

I would like to force garbage collection on the popup so I can properly test my own code.

public void MemoryLeak_Popup()
{
    WeakReference weakReferencePopup;
    WeakReference weakReferenceChild;

    {
        Popup popup = new Popup();
        popup.Child = new StackPanel();

        popup.IsOpen = true;
        popup.IsOpen = false;

        weakReferencePopup = new WeakReference(popup);
        weakReferenceChild = new WeakReference(popup.Child);

        popup.Child = null;
    }

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

    Assert.IsFalse(weakReferenceChild.IsAlive, "Memory leak for the popup's child.");
    Assert.IsFalse(weakReferencePopup.IsAlive, "Memory leak for the popup.");
}
CBFT
  • 273
  • 2
  • 14
  • @ThomasWeller: I think the OP is talking about [this Popup class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.popup). The way he collecting should be perfectly fine. – Andre Kampling Jun 23 '21 at 19:53
  • I am using System.Windows.Controls.Primitives.Popups. @ThomasWeller I removed the references to my code when trying to isolate the memory leak. – CBFT Jun 23 '21 at 20:02
  • Does this answer your question? [Collect objects still in scope - GC.Collect](https://stackoverflow.com/questions/6425052/collect-objects-still-in-scope-gc-collect) You need to run `GC.Collect` from **outside** the function, otherwise GC still thinks it's in scope. But why would you want to do this anyway, just put in a `using` block like you're supposed to. There is no point unit-testing the GC, you may as well unit-test `2+2=4` – Charlieface Jun 24 '21 at 08:30
  • @Charlieface: It is an interesting question why it behaves different. The OPs question has nothing to do with `using` blocks and `Dispose`. The OP is setting the reference of the `Child` to `null` to let the GC reclaim the memory. If you would call `Dispose` the object is not collected, it is still alive. `Dispose` is just a regular method and has nothing to do with the GC. The GC knows the Finalizer. [See this nice explanation](https://stackoverflow.com/a/21603787/8051589). If not it would not be possible to provide a boolean propery like `IsDisposed` for example. – Andre Kampling Jun 24 '21 at 09:57
  • @AndreKampling I'm very much aware of the way the GC works, and that `Dispose` doesn't garbage collect. I'm just pointing out that this whole unit test is flawed in the first place: you don't need to unit-test the GC, and you shouldn't worry about it if you're disposing correctly anyway. It's certainly possible that the runtime is holding a reference somewhere, perhaps in a register, and the only way to verify this is to execute `GC.Collect` outside the function, and add `NoInlining` to the function. Without this then nothing has been proven anyway – Charlieface Jun 24 '21 at 10:40
  • 1
    I'm not unit testing the garbage collection. I'm unit testing my user control and making sure it doesn't cause a memory leak. However, the garbage collection not working as expected causes my unit test to fail. To run the unit test I want to on my code, I need to have the popup's child be garbage collected. I don't care much about the popup itself. I simplified my code before posting it so I took out references to my custom user control. – CBFT Jun 24 '21 at 13:26

0 Answers0