调用 Application.Exit() 后,应用程序仍在内存中运行
Posted
技术标签:
【中文标题】调用 Application.Exit() 后,应用程序仍在内存中运行【英文标题】:Application is still running in memory after Application.Exit() is called 【发布时间】:2014-07-31 03:24:25 【问题描述】:我正在构建的应用程序在使用Application.Exit()
关闭后仍在内存中运行(在任务管理器中检查)。因此,当我在如上所述关闭它后再次运行它时,我收到此错误“一次只有一个实例”。你能告诉我如何完全关闭我的应用程序吗?
【问题讨论】:
您使用的是Microsoft.Office.Interop
吗? (例如 Excel)
您是否尝试在它退出后附加到它,暂停线程并查看仍然处于活动状态的内容?不确定应用程序退出语义,但前台线程通常不想退出,除非明确结束
Process.GetCurrentProcess().Kill();
怎么样
谢谢琼斯,这很有效。
【参考方案1】:
这似乎是一个 Windows 应用程序,您正在调用 System.Windows.Forms.Application.Exit() 但有一个线程仍在后台运行。你试过了吗
Application.ExitThread();
Environment.Exit();
您可以像 Jonesy 提到的那样终止该进程,如果它是与当前正在运行的进程不同的应用程序,则传入该进程的进程 ID。
为此,您需要使用 System.Diagnostics.Process 命名空间并遍历当前正在运行的进程以获取正确的 pid,然后对该 pid 调用 kill。
【讨论】:
谢谢罗伯特,帮了大忙。【参考方案2】:有一次我有奇怪的行为(在Application.Exit()
期间崩溃/冻结),我使用了Process.GetCurrentProcess().CloseMainWindow()
。
该函数位于 System.Diagnostics
命名空间中,并且似乎比 Kill()
更好,因为它不会强制它以相同的方式退出。
【讨论】:
【参考方案3】:由于使用了Foreground Thread和Lybda Expession thread,所以,线程会继续运行,直到最后一个前台线程终止。换句话说,当所有前台线程都停止时,应用程序就会关闭。 这就是为什么应用程序不会等到后台线程完成,而是会等到所有前台线程都终止。 所以在这种情况下,我们必须使用
显式停止所有正在运行的线程Environment.Exit(Environment.ExitCode);
这样可以完美地管理内存,没有内存泄漏。
【讨论】:
这不会为 3 岁接受的答案添加任何内容。 这个答案帮助我处理了接受的答案中不存在的返回码(Environment.ExitCode),如果输入会导致错误,它会在 2020 年显示。【参考方案4】:如果该过程仍处于待处理状态,则意味着您没有正确处理资源。
使用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
中设置表单以在任何地方访问它的黑客,不要处置它,否则您正在处置一个已经处置的表单。
【讨论】:
以上是关于调用 Application.Exit() 后,应用程序仍在内存中运行的主要内容,如果未能解决你的问题,请参考以下文章
Application.Exit() - 关闭表单后应用程序仍在运行
Application.Exit()结束程序,但线程还在的解决方法。
Winforms:Application.Exit vs Environment.Exit vs Form.Close
c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.Environmen