如果该过程仍处于待处理状态,则意味着您没有正确处理资源。
使用Application.Exit()或要求系统执行Environment.Exit(0)可能会在发生错误时登录系统,如果你想知道如何正确关闭进程而不是依赖Application.Exit()只关闭一个线程并保持您的应用程序运行,您必须知道如何收集这些垃圾
您可以重新实现Dispose 方法来处理服务、套接字、流,以及几乎所有具有.Dispose 可用的东西。
public class MyClass: IMyClass, IDisposable
{
private bool _disposed = false;
// ...
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// dispose your stuff you created in this class
// do the same for other classes
// some examples
/*
_webClient.Dispose();
_connector.DataAvailable -= ConnectorHasDataComing
_socket.Dispose();
_timer.Dispose();
_taskLogs.ForEach(x => {
x.Token.Cancel();
x.Task.Wait();
x.Task.Dispose();
});
*/
}
// dispose native events
_disposed = true;
}
如果您使用System.Threading.Thread 或System.Threading.Tasks.Task 或System.IO.MemoryStream(或其他类型的流 - 写入器/读取器),以及其他需要CancellationTokenSource 的东西。如果您在处置类时在类中创建了资源,请在调用.Dispose()之前使用Token.Cancel() 方法让它知道它的父级正在被处置并为它提供.Wait()。
public async Task Run(CancellationTokenSource cancellationTokenSource)
{
// ...
while (Running) {
if (cancellationTokenSource.IsCancellationRequested) return;
// ....
}
// ....
using (var reader = new WaveFileReader(tempFile))
{
reader.Position = 0;
await reader.CopyToAsync(fileWriter,81920, cancellationTokenSource.Token);
}
}
当我的调试在关闭应用程序后仍处于待处理状态时,我使用诊断工具发现了我的问题。
如果您使用 CPU 使用率,您可以单击 Break All 并设置断点。
然后您可以查看分析器并找到最重要的功能,您可能会发现您的表单已被释放,但您有一个调用表单上的字段的线程或任务。
就我而言,我使用了一个文件写入器,并在该类中实现了 IDisposable,但它有时是关于或实际使用 .copyTo 在文件读取器与其自身之间进行数据传输,因此它处于挂起状态而不会引发异常。
点击一个事件后,点击Go to Source code并放置一个断点,你可能会看到你的代码存放的事件。
否则,您可以在同一工具中使用标签Memory Usage 拍摄快照并查看堆和对象差异或标签CPU Usage 并查看记录的配置文件。我通过这种方式找到了我的copyTo 问题。
您也可以使用Throw on all exceptions 运行您的应用程序
在处理时确保没有人记得表单或其实例。
另外,如果你使用表单事件_FormClosing
确保您有一个模式来取消表单关闭,返回并设置e.Cancel = true;,但如果表单正在关闭,请不要设置e.Cancel = true。并且不要在您自己处理的_FormClosing() 事件中调用this.Close()。
之后,您可以.Dispose() 您的东西,但请确保没有 Dispose 方法像调用组件那样回调表单,因为它们正在被释放或已经被释放。
对于那些使用在var instance 中设置表单以在任何地方访问它的黑客,不要处置它,否则您正在处置一个已经处置的表单。