【问题标题】:Application is still running in memory after Application.Exit() is called调用 Application.Exit() 后,应用程序仍在内存中运行
【发布时间】:2014-07-31 03:24:25
【问题描述】:

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

【问题讨论】:

  • 您使用的是Microsoft.Office.Interop吗? (例如 Excel)
  • 您是否尝试在它退出后附加到它,暂停线程并查看仍然处于活动状态的内容?不确定应用程序退出语义,但前台线程通常不想退出,除非明确结束
  • Process.GetCurrentProcess().Kill();怎么样
  • 谢谢琼斯,这很有效。

标签: c# memory exit-code


【解决方案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.ThreadSystem.Threading.Tasks.TaskSystem.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 中设置表单以在任何地方访问它的黑客,不要处置它,否则您正在处置一个已经处置的表单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-03
      • 2013-02-03
      • 2011-04-02
      • 2021-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多