防止 Windows 服务器暂停我的进程

Posted

技术标签:

【中文标题】防止 Windows 服务器暂停我的进程【英文标题】:Prevent windows server from suspending my process 【发布时间】:2021-06-22 13:47:43 【问题描述】:

我用 C# 开发了一个在 Windows 服务器上运行的程序(winforms 应用程序,而不是服务)。

程序根据来自服务器外部的请求多次启动。

我不时看到该程序由于未知原因而“暂停”。我认为这与缺乏资源有关,但不确定。

如何防止 Windows 暂停我的程序?

更新 需要明确的是,我知道程序崩溃并且没关系。我要问的不是如何提高性能\防止崩溃,而是如何从进程列表中删除进程\防止这种挂起状态?

【问题讨论】:

您能更具体地说明问题吗?程序在暂停时是否会停止执行某些操作?是后台进程还是交互式程序? 注意:有一个 Windows 操作系统错误会导致程序卡在挂起状态。请运行窗口更新,安装任何缺少的主要版本,然后重新启动。如果问题消失,请告诉我们。 windows server(2019)更新了,问题依旧。你有那个 windows 错误的参考吗? 【参考方案1】:

取决于您的硬件/软件配置,很难知道您的瓶颈在哪里。

我建议改为使用多线程/任务应用程序,您可以在其中控制线程并分配优先级、资源、停止、恢复、中止等......

在命令控制台上使用启动并检查是否发生相同但参数高:

start /HIGH <ProgramPath>

Read more how to change priority on executables

Task Scheduler on windows servers MSDN -> Priority

(这只是一个意见,开始挖掘其他解决方案。)

【讨论】:

谢谢,不过,我不希望提高性能。只是“信号”窗口,这个过程不应该被暂停。【参考方案2】:

在服务启动之前,您必须在服务的构造函数中将ServiceBase.CanPauseAndContinue属性设置为False

注意副作用是:

如果 CanPauseAndContinue 为 false,则 SCM 不会通过 Pause 或 继续向服务请求,所以 OnPause 和 OnContinue 即使实现了方法也不会被调用。在单片机中, 当 CanPauseAndContinue 时,Pause 和 Continue 控件被禁用 是假的。

欲了解更多信息,请参阅Microsoft Doc

【讨论】:

该程序不是一个服务,而是一个winforms应用程序。我已经编辑了问题以澄清它。 也许应该是……它有用户点击的界面吗?这不是让它退出暂停吗?使用中怎么可能挂起? 它不能,该程序托管了一个 Web 浏览器,该浏览器会根据它托管的站点“泄漏”内存。因此,对于每个请求,都会启动一个新进程,并在完成后关闭。【参考方案3】:

有多种方法可以让应用保持唤醒状态。

一种方法是请求延期,然后仅在完成后标记延期完成。

首先,您需要一个延迟对象,该对象将保留在您的流程范围内

SuspendingDeferral deferral

那你需要覆盖OnSuspending

async protected void OnSuspending(object sender, SuspendingEventArgs args)

    deferral = args.SuspendingOperation.GetDeferral();
    await SuspensionManager.SaveAsync();

然后你需要在你的进程完成任何它正在做的事情时标记延迟完成

    if (deferral is not null)  deferral.Complete(); 

详情请见the Microsoft docs

有关其他方法的讨论,请参阅此线程: How to Disable UWP App Suspension?

【讨论】:

这不是 UWP,而是问题中所述的 winforms 程序。据我所知,winforms 没有 OnSuspending \ SuspensionManager。【参考方案4】:

从技术上讲,该进程已暂停,但如果您查看 32K 的内存消耗,您可以知道它没有暂停。您的进程确实因未处理的异常而崩溃,进而触发 Windows 错误报告进行内存转储。

这涉及到一些内核魔法,它使内核(系统进程)中的进程句柄保持活动状态。这不是什么大问题或内存泄漏,因为该进程已经终止。只有PEB(进程环境块)32K,主要包括命令行、加载的dll和环境变量。

我不会担心暂停的进程,但为什么您的进程会因未处理的异常而崩溃。这甚至可以是一个功能,让程序员通过查看任务管理器中的大量挂起进程列表来意识到他们的进程确实崩溃了 ;-)。

由于它是一个 .NET 应用程序,您会在应用程序事件日志中找到一个进程确实崩溃的通用错误消息,以及一个带有更多异常详细信息的 .NET 运行时记录的错误消息。

也许这已经足以让您继续解决问题。如果不是,您可以配置 WER 以通过注册表设置 (https://docs.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps) 创建完整的内存转储。现在,您为每个“挂起”的进程都有一个完整的内存转储,您可以将其加载到 Visual Studio 中以进一步查看问题所在。

要进一步检查谁持有您的进程句柄仍处于打开状态,您可以使用句柄,例如ProcessHacker(更好的 Process Explorer)https://processhacker.sourceforge.io/nightly.php

如果发生其他事情,您可以使用此工具查看谁持有任何未处理的进程句柄以打开您的进程。但我强烈怀疑它是 Windows 内核。

【讨论】:

是的,这绝对是我程序中的一个第三方库的迷恋。这就是我打开几个进程的原因。您写道:“我不会担心暂停的进程,但为什么您的进程会因未处理的异常而崩溃。” - 但我不担心崩溃(我可以处理它),而是从进程列表中完全删除进程。 32K 听起来不是很多,但一段时间后,我有数百个进程处于“暂停”状态。所以问题是——我怎样才能删除进程或信号窗口来删除进程, 修复错误或处理异常或在您的 app.config 中启用 以继续运行,即使出现未处理的异常。 我已经尝试过了 (legacyUnhandledExceptionPolicy) - 没有成功。我无法修复错误或处理异常,因为它是第三方代码 崩溃的堆栈跟踪是什么?

以上是关于防止 Windows 服务器暂停我的进程的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 上的 Python Popen 子进程中暂停 FFmpeg 编码

防止计时器在后台模式下暂停

如何在 Visual Basic 中暂停 System.Timer?

.Net 2.0 Windows 服务进程通信:数据库还是 IPC?

启动时暂停 Windows 10 应用商店应用

多线程和进程信令