调用Application.Exit()后,应用程序仍在内存中运行

时间:2014-07-31 03:24:25

标签: c# memory exit-code

我正在构建的应用程序在使用Application.Exit()关闭后仍在内存中运行(在任务管理器中检查)。正因为如此,当我如上所述关闭它后再次运行它时,我收到此错误“一次只有一个实例”。你能告诉我如何完全关闭我的申请吗?

4 个答案:

答案 0 :(得分:12)

似乎这是一个Windows ap,你正在调用System.Windows.Forms.Application.Exit()但是仍有一个线程在后台运行。你试过吗

Application.ExitThread();

Environment.Exit();

您可以像Jonesy提到的那样终止进程,如果它是一个单独的应用程序而不是当前正在运行的进程,则传入进程的进程ID。

为此,您需要使用System.Diagnostics.Process命名空间并遍历当前正在运行的进程以获取正确的pid,然后在该pid上调用kill。

答案 1 :(得分:2)

有一次我有奇怪的行为(在Application.Exit()期间崩溃/冻结),我使用了Process.GetCurrentProcess().CloseMainWindow()

该函数位于System.Diagnostics命名空间中,似乎优于Kill(),因为它不会强制它以相同的方式退出。

答案 2 :(得分:1)

如果进程仍处于挂起状态,则意味着您没有正确处理资源。

使用 Application.Exit() 或要求系统执行 Environment.Exit(0) 可能会在发生错误时记录在系统中,您最好知道如何正确关闭进程而不是依赖于 {{1} },如果你只想关闭一个线程并保持你的应用程序运行,你必须知道如何收集这些垃圾

您可以重新实现 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.ThreadSystem.Threading.Tasks.Task(或其他类型的 Stream - Writer/Reader),以及其他需要 System.IO.MemoryStream 的。如果您在释放类时在类中创建了资源,请在调用 CancellationTokenSource

Token.Cancel() 方法让它知道它的父级正在被释放并为它.Wait() >
.Dispose()

当我的调试在关闭应用程序后仍有待处理时,我使用诊断工具发现了我的问题。

enter image description here

如果您使用 CPU 使用率,您可以点击 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); } } 并设置断点。 然后,您可以查看分析器并找到您的主要功能是什么,您可能会发现您的表单已被释放,但您有一个线程或任务来调用表单上的字段。

enter image description here

就我而言,我使用的是文件写入器,并在该类中实现了 IDisposable,但有时是关于或实际使用 Break All 在文件读取器与其自身之间传输数据,因此它处于挂起状态而不会引发异常.

enter image description here

点击一个事件后,点击 .copyTo 并放置一个断点,您可能会看到您的代码存储在其中的事件。

否则,您可以在同一工具中使用选项卡 Go to Source code 拍摄快照并查看堆和对象差异或选项卡 Memory Usage 并查看记录的配置文件。我就是这样发现我的 CPU Usage 问题的。

您还可以使用 copyTo 运行您的应用 enter image description here

在处理时确保没有人记得该表单或其实例。

此外,如果您使用表单事件 Throw on all exceptions

确保您有一个模式来取消关闭表单,返回并设置 _FormClosing 但如果表单正在关闭,请不要设置 e.Cancel = true;。并且不要在您自己处理的 e.Cancel = true 事件中调用 this.Close()

之后,你可以_FormClosing()你的东西,但确保没有 Dispose 方法像调用组件那样回调表单,因为它们正在被释放或已经被释放。

对于使用将表单设置在 .Dispose() 中的黑客可以在任何地方访问它的人,不要处置它,否则你正在处置一个已经处置的表单。

答案 3 :(得分:0)

由于使用Foreground Thread和Lybda Expession线程所以,线程将继续运行,直到最后一个前台线程终止。换句话说,当所有前台线程都停止时,应用程序将关闭。 这就是为什么应用程序不会等到后台线程完成的原因,但它会等到所有前台线程都被终止。 因此,在这种情况下,我们必须使用

显式停止所有正在运行的线程

Build

这样可以很好地管理内存,没有内存泄漏。