【发布时间】:2020-09-16 04:23:10
【问题描述】:
现在我的同事之间就需要处理 C# 文件类型的位置进行了辩论。 (https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose)
查看下面的代码,当前 File.Delete 在 if(disposing) 部分中,它被认为是托管对象。有些人认为它需要在循环之外并且需要放置在非托管对象中。
~someService() => Dispose(false);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
GC.Collect();
}
bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
tempFilePaths?.ToList().ForEach(f =>
{
if (File.Exists(f))
{
File.Delete(f);
}
});
this._engine?.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
this._fields = null;
disposed = true;
}
【问题讨论】:
-
归结为当对象没有被显式释放并且不再使用对象并且GC调用终结器是否应该删除文件时。如果在任何情况下都应该将其删除,则将其放在 if 块之外。然而,finalizer 应该避免做繁重的工作,因为 GC 是单线程的,并且一个缓慢的 finalizer 会减慢 GC 的工作。另一个问题是你永远不应该打电话给
GC.Collect。让 GC 在有时间的时候处理清洗。 -
但另一方面,我不想通过将托管对象放在 if(disposing) 之外来查看 ObjectDisposedException。如果需要快速释放内存,GC.Collect 似乎是必要的,所以我想知道为什么不应该调用它的强有力的推理。谢谢。
-
为什么需要快速收集内存?当内存压力高时,GC 会自动收集。垃圾收集是昂贵的。因此,在处理此类对象的任何时候触发它,不仅是为了释放对象本身,而且是为了释放进程中所有不需要的对象,可能会对应用程序性能产生负面影响。此外,它还违反了单一职责原则,因为 ExtractionService 不应关注进程内存管理。
-
这确实是特定于应用程序的,但当前设计的问题是,为前一个任务分配的内存确实会阻止下一个任务完成作业,因为数据一次性进入会导致巨大的内存被占用,需要移除。但是让我更多地搜索一下 GC.Collect 的副作用,谢谢。
-
我会说你不应该删除终结器中的文件,因为它会对你的应用程序的性能产生负面影响,终结器应该很快,所以绝对不应该在终结期间执行。但是如果由于某种原因
Dispose未被调用,文件将不会被删除。但是你也不能依赖终结器,所以我认为最好的方法是删除Dispose(true)中的文件并为特殊情况制定备份策略(例如,如果你保证只有一个,则在应用程序启动时执行清理应用实例正在运行)。