2

I am using the dotMemoryUnit to prove the my DbContext object is getting garbage collected properly.

I feel that this code should work properly in a unit test, but the test always fails. The only thing I can guess is EF Core is holding a reference somewhere.

Edit: I'm not sure the suggested question addresses this problem as this is .Net Core and not .Net Framework. The documentation for GC.Collect()'s default is forced and the documentation says nothing about hints.

Edit 2: I did find the answer below.

Thoughts?

    public class UnitTest1
    {
        public UnitTest1(ITestOutputHelper output)
        {
            DotMemoryUnitTestOutput.SetOutputMethod(output.WriteLine);
        }

        [Fact]
        [DotMemoryUnit(FailIfRunWithoutSupport = false)]
        public void DummyContext_DisposesContextOnGarbageCollect()
        {
            // Arrange
            var options = new DbContextOptionsBuilder<DummyContext>()
                .UseSqlServer("data source=ASqlServer;Integrated Security=true");

            using (var ctx = new DummyContext(options.Options))
            {
                // do nothing
            }

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

            dotMemory.Check(
                memory =>
                    Assert.Equal(
                        0,
                        memory.GetObjects(where => where.Type.Is<DummyContext>()).ObjectsCount));
        }

        private class DummyContext : DbContext
        {
            public DummyContext(DbContextOptions options)
                : base(options)
            {
            }
        }
    }

Mike Therien
  • 928
  • 3
  • 10
  • 25
  • 1
    Just to be sure, when you do the check *before* you create a new context, the count is 0? – Hans Kesting Jan 02 '20 at 21:19
  • https://stackoverflow.com/questions/888280/garbage-collection-does-not-reduce-current-memory-usage-in-release-mode-why – mxmissile Jan 02 '20 at 21:24
  • Duplicate of [Garbage Collection does not reduce current memory usage - in release mode. Why?](https://stackoverflow.com/questions/888280/garbage-collection-does-not-reduce-current-memory-usage-in-release-mode-why) – Herohtar Jan 02 '20 at 21:26
  • @HansKesting - Yes the value is zero – Mike Therien Jan 02 '20 at 21:44
  • 2
    `GC.Collect();` is more of a hint or suggestion than a command. The GC can respond by shrugging if it doesn't think a collection is necessary. –  Jan 02 '20 at 22:14

1 Answers1

2

After a little more research, I have found the answer in this post from Jet Brains:

Since all of our logic is being run in one method (our test method), the garbage collector will not clean up local variables that are still available in the context of our function.

The post suggests wrapping the code in an action method.

For others that may have this problem, below is my new test method:

[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = false)]
public void DummyContext_DisposesContextOnGarbageCollect()
{
    var isolator = new Action(
        () =>
        {
            // Arrange
            var options = new DbContextOptionsBuilder<DummyContext>()
                .UseSqlServer("data source=ASqlServer;Integrated Security=true");

            using (var ctx = new DummyContext(options.Options))
            {
                // do nothing
            }
        });

    isolator();

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

    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);

    dotMemory.Check(
        memory =>
            Assert.Equal(
                0,
                memory.GetObjects(where => where.Type.Is<DummyContext>()).ObjectsCount));
}
Mike Therien
  • 928
  • 3
  • 10
  • 25