【发布时间】:2021-01-13 21:41:52
【问题描述】:
我有一个异步加载数千行的 Blazor 页面。在 Visual Studio 中,我看到一旦加载此数据,我的 Blazor 应用程序会在内存中使用多个 gig。到目前为止没有问题。但是,换页时不会再次释放内存。
所以我实现了IDisposable,它取消了异步操作并将我的数据列表设置为空,但这似乎没有按预期工作。页面改变时调用Dispose方法,但内存消耗保持在1GB。
有人知道我做错了什么吗?
这是我的代码:
public List<ErloesKalkulatorServiceResult> Daten { get; set; } = new List<ErloesKalkulatorServiceResult>();
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
Daten = null!;
cancellationToken?.Cancel();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
~ErloesKalkulator()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false);
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
【问题讨论】:
-
运行时不需要释放它所获得的内存,因为它会尝试将它重用于新的分配
-
是的,但我不希望整个应用程序永久阻止此内存。因为所有其他页面仅使用几 MB。所以 1 场演出实在是太过分了。
-
仅将集合设置为
null并不总是足够的。首先,当您调用Dispose时,GC 不会释放资源。相反,它可以随时发生。 GC 可以访问实时 (JIT) 编译器和运行时维护的活动根列表。使用这个列表,GC 会创建一个图,其中包含所有可从根到达的对象。如果有单个实例维护对您的项目的强引用,并且该单个实例可从根访问,则无法收集该项目。 -
一个例子是当项目订阅了一个可达实例的事件时。还有其他场景。在更改页面或调用
Dispose之后,您应该使用像 Visual Studio 调试工具这样的内存分析器来获取和检查当前堆中的快照,以查找占用内存的对象。分析器还会向您显示参考图。还要验证Dispose是否被实际调用。 -
在您的情况下,不需要实现
IDisposable。如果你理解了前面关于 GC 如何决定收集哪些对象的解释,你就会知道你只需要删除对拥有类型的所有引用(例如,从视图中删除页面,取消挂钩事件处理程序)就可以做到这一点实例及其所有引用的实例(子树)符合垃圾回收条件。但是当存在 GC 无法跟踪(管理)的非托管对象时,必须显式处置这些对象,以便让 GC 知道该实例(及其子树)是合格的。
标签: c# blazor dispose blazor-server-side