是否应在 Windows 服务停止之前处理一次性物品?

Should disposable objects be disposed before a Windows Service stops?

this 线程,Dispose() 必须 显式 调用一次性对象。

Windows 服务停止时会发生什么?这些对象使用的资源是否自动释放?还是应该在服务停止之前处理掉它们:

public void Stop()
{
    cancellationTokenSource.Cancel();
    waitForAllTasksToExit();
    cancellationTokenSource.Dispose();
}

"It's a good practice to dispose","They should be freed when the service stops"也是我的想法。但是参考文档有没有具体的答案呢?

作为最佳实践,必须在一次性资源上显式调用 Dispose()。但是,当您停止 windows 服务时,它会向所有底层进程(即您的 .NET 代码)发送一条控制消息,并停止或卸载所有 AppDomain。因此,所有使用的资源和内存都应该得到释放

这取决于“这些对象使用的资源”是什么。 Dispose 方法本身不会在进程退出时调用,但除了 Dispose 之外,大多数包含“非托管”资源的对象也有终结器。 Finalizer 将在进程退出时调用,但可能不会在进程崩溃时调用。现在,在进程退出(或崩溃)时 the following 发生:

Any resources allocated by the process are freed.

All kernel objects are closed.

内核对象是例如文件句柄、套接字等。因此,即使进程崩溃并且终结器不是 运行(或者根本没有终结器)- 文件或 database\network 连接之类的东西仍将被 OS.

关闭

您可能对非托管资源有更广泛的定义。非托管意味着不受 .NET Framework 垃圾收集器管理。例如,如果我在创建某个对象时在磁盘上创建一个文件,并在处理该对象时删除该文件——您可能会说这也是“非托管”资源。 OS 不知道这样的资源,如果我没有实现终结器或由于进程崩溃而没有调用终结器,它不会被“清理”。

总而言之 - 如果对象实现 IDisposable - 甚至在进程退出之前就将其处理掉。您可能不知道该对象开发人员的意图,无论它是否具有终结器 - 因此最好始终在进程退出之前显式处置它。

@Evk已经给出了答案,但我不是很清楚。经过对文档的广泛搜索,我参考文档整理了以下答案。

长答案:

当服务停止时,它的资源将被垃圾收集器释放。

那么实现 IDisposable 的对象呢?请问unmanaged resources be freed? No. From Dispose Pattern:

The GC was specifically not designed to manage such unmanaged resources, which means that the responsibility for managing unmanaged resources lies in the hands of the developers.

那么,非托管资源会怎样?他们永远不会被释放吗?

还有机会

Object declares a virtual method Finalize (also called the finalizer) that is called by the GC before the object’s memory is reclaimed by the GC and can be overridden to release unmanaged resources.

然而这有一些 drawbacks:

  1. 对象的终结器在 GC 检测到对象符合收集条件后的一段不确定时间后调用。
  2. 终结器在两次收集之间 运行,因此直到下一轮垃圾收集才会释放对象的内存。

虽然 documentation 说实现 IDisposable.Dispose 的对象应该重写 Finalize 方法或将托管对象包装在 SafeHandle 中,这样如果消费者忘记调用 Dispose,非托管资源仍然被释放;我们还是有麻烦的。

From the DocsFinalize 方法仅在派生类型覆盖它时被调用。

那么,如果开发者没有实施上面的 2(FinalizeSafeHandle)怎么办?然后我们有一个问题,没有人释放未管理的资源(至少文档没有说)。

TLDR

资源可能会或可能不会被释放(取决于上述情况)。因此,在服务的 Stop 方法中处理所有一次性对象(尚未处理)。