首页 > 解决方案 > 为什么 EF Core 2.2.6 不进行垃圾收集?

问题描述

我正在使用 dotMemoryUnit 来证明我的 DbContext 对象正在正确收集垃圾。

我觉得这段代码在单元测试中应该可以正常工作,但是测试总是失败。我唯一能猜到的是 EF Core 在某处持有引用。

编辑:我不确定建议的问题是否解决了这个问题,因为这是 .Net Core 而不是 .Net Framework。GC.Collect() 的默认文档是强制的,文档没有说明任何提示。

编辑2:我确实在下面找到了答案。

想法?

    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)
            {
            }
        }
    }

标签: c#garbage-collectionentity-framework-coredotmemory

解决方案


经过更多研究,我在Jet Brains的这篇文章中找到了答案:

由于我们所有的逻辑都在一个方法(我们的测试方法)中运行,垃圾收集器不会清理在我们的函数上下文中仍然可用的局部变量。

该帖子建议将代码包装在操作方法中。

对于其他可能有此问题的人,以下是我的新测试方法:

[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));
}

推荐阅读