在Windows服务停止前,应该处理一次性对象吗?

8

根据这个帖子,对于可释放对象,必须显式地调用Dispose()方法。

当Windows服务停止时会发生什么?这些对象使用的资源会自动释放吗?还是应该在服务停止之前进行释放,就像这样:

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

"及时释放资源是一个好习惯""当服务停止时应该释放它们",我也这样认为。但是根据文档是否有具体的答案呢?


3
据我所知,当程序结束时,其所有内存都会被释放。你有不同的经验吗? - Camilo Terevinto
2
@CamiloTerevinto,这不仅仅是关于内存的问题 - 打开(数据库)连接、文件访问等也在Dispose中处理。 - Toshi
2
所有“本地”于您的进程(内存、窗口句柄等)的资源将自动释放。但是最好还是处理所有对象:正如@Toshi所说,您必须考虑一些与您的进程有关的外部对象。例如,数据库服务器将认为未处理的连接仍然处于活动状态(并最终将使用自己的方式来检测该连接不再活动),因此需要进行处理。 - Gian Paolo
@YohDeadfall 这个问题涉及到意外终止。但我正在询问停止服务时调用的名为Stop()方法的服务。 - Xpleria
@NeilPatrao 是的,但答案说的是未被处理的资源会发生什么。这正是你所问的。 - Yoh Deadfall
显示剩余4条评论
3个回答

5
这取决于“对象使用的资源”的含义。 Dispose 方法本身不会在进程退出时被调用,但是除了 Dispose 之外还包含“非托管”资源的大多数对象都有终结器。终结器将在进程退出时被调用,但它可能不会在进程崩溃时被调用。现在,在进程退出(或崩溃)时 发生以下情况:

由进程分配的任何资源都将被释放。

所有内核对象都将被关闭。

内核对象例如文件句柄、套接字等等。因此,即使进程崩溃并且未运行终结器(或根本没有终结器),操作系统仍将关闭诸如文件或数据库/网络连接之类的内容。

您可能对未托管资源有更广泛的定义。未托管的意思是不受.NET Framework垃圾回收器管理。例如,如果我在创建某个对象时在磁盘上创建文件,并且在处理此对象时将删除此文件 - 您可能会说这也是“未托管”的资源。这种资源未知于操作系统,如果我没有实现终结器或由于进程崩溃而未调用终结器,则不会被“清理”。
总之 - 如果对象实现了IDisposable - 即使在进程退出之前,请立即处理它。您可能不知道该对象开发人员的意图,无论它是否具有终结器 - 因此最好始终明确处理它,即使在进程退出之前。

2

@Evk已经给出了答案,但对我来说不太清楚。在广泛查阅文档后,我参考文档编写了以下答案。

详细回答:

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

那么实现IDisposable的对象呢?非托管资源会被释放吗?不会。根据Dispose Pattern

GC并没有专门设计来管理这些非托管资源,这意味着管理非托管资源的责任在开发人员手中。

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

还有一线希望

Object声明了一个虚方法Finalize(也称终结器),在GC回收对象内存之前调用该方法以释放非托管资源。

然而这有一些缺点

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

虽然文档说实现IDisposable.Dispose的对象应该覆盖Finalize方法或将托管对象包装在SafeHandle中,以便如果消费者忘记调用Dispose,非托管资源仍会被释放;但我们仍可能遇到麻烦。

根据文档,只有派生类型重写了Finalize方法才会调用它。

那么,如果开发人员都没有实现上述两种方法(FinalizeSafeHandle),会怎样呢?那么我们就有问题了,没有人来释放非托管资源(至少文档没有说明)。

简而言之

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


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

4
未进行管理的资源只有在调用Dispose时才会被释放,这方面怎么处理? - Uwe Keim
1
@UweKeim 那个也会被触发吗? - Camilo Terevinto
1
@Rahul 当你重新启动操作系统时,未被处理的非托管资源将被释放。 - Toshi
2
@Rahul:非托管资源不仅包括内存,还可以是数据库连接、文件流、网络连接。如果它们没有被释放,可能会锁定文件或导致数据库或网络出现问题。建议重新启动操作系统听起来很奇怪。有些服务器运行多年而无需重启,这不应该作为适当处理模式的替代方案。 - Tim Schmelter
1
@Rahul:你提出了一个非常具体的C问题,OP问这是否会导致内存泄漏(请注意,你不能将C与C#进行比较),你为什么认为这与其他所有未受管控的资源都是相同的情况? - Tim Schmelter
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接