我正在构建的应用程序在使用Application.Exit()
关闭后仍在内存中运行(在任务管理器中检查)。正因为如此,当我如上所述关闭它后再次运行它时,我收到此错误“一次只有一个实例”。你能告诉我如何完全关闭我的申请吗?
答案 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.Thread
或 System.Threading.Tasks.Task
(或其他类型的 Stream - Writer/Reader),以及其他需要 System.IO.MemoryStream
的。如果您在释放类时在类中创建了资源,请在调用 CancellationTokenSource
.Wait()
>
.Dispose()
当我的调试在关闭应用程序后仍有待处理时,我使用诊断工具发现了我的问题。
如果您使用 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);
}
}
并设置断点。
然后,您可以查看分析器并找到您的主要功能是什么,您可能会发现您的表单已被释放,但您有一个线程或任务来调用表单上的字段。
就我而言,我使用的是文件写入器,并在该类中实现了 IDisposable,但有时是关于或实际使用 Break All
在文件读取器与其自身之间传输数据,因此它处于挂起状态而不会引发异常.
点击一个事件后,点击 .copyTo
并放置一个断点,您可能会看到您的代码存储在其中的事件。
否则,您可以在同一工具中使用选项卡 Go to Source code
拍摄快照并查看堆和对象差异或选项卡 Memory Usage
并查看记录的配置文件。我就是这样发现我的 CPU Usage
问题的。
此外,如果您使用表单事件 Throw on all exceptions
确保您有一个模式来取消关闭表单,返回并设置 _FormClosing
但如果表单正在关闭,请不要设置 e.Cancel = true;
。并且不要在您自己处理的 e.Cancel = true
事件中调用 this.Close()
。
之后,你可以_FormClosing()
你的东西,但确保没有 Dispose 方法像调用组件那样回调表单,因为它们正在被释放或已经被释放。
对于使用将表单设置在 .Dispose()
中的黑客可以在任何地方访问它的人,不要处置它,否则你正在处置一个已经处置的表单。
答案 3 :(得分:0)
由于使用Foreground Thread和Lybda Expession线程所以,线程将继续运行,直到最后一个前台线程终止。换句话说,当所有前台线程都停止时,应用程序将关闭。 这就是为什么应用程序不会等到后台线程完成的原因,但它会等到所有前台线程都被终止。 因此,在这种情况下,我们必须使用
显式停止所有正在运行的线程 Build
这样可以很好地管理内存,没有内存泄漏。