为什么终止Excel进程是件坏事

本文关键字:进程 终止 Excel 为什么 | 更新日期: 2023-09-27 18:24:15

我看过很多文章和问题,关于如何确保Excel在您希望的时候退出,并且该过程不会保持活力。这是一篇知识库文章,介绍了该问题和Microsoft推荐的解决方案。本质上:

'close files
'Quit Excel
xlApp.quit()
'Release and collect garbage
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp)
GC.Collect()
GC.WaitForPendingFinalizers()

许多人不建议扼杀这个过程;看见如何正确清理Excel互操作对象以及理解.net 中的垃圾回收

另一方面,许多人不建议使用GC.Collect。请参阅使用GC.CCollect()有什么错?

根据我的经验,杀死这个过程是确保Excel消失的最快、最简单的方法。我的代码只会杀死它启动的确切过程,而不会杀死其他过程。我确保关闭所有打开的工作簿,退出应用程序并释放xlApp对象。最后,我检查一下这个过程是否还活着,如果是的话,就把它杀死

<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
ByRef lpdwProcessId As Integer) As Integer
    End Function
Sub testKill()
    'start the application
    Dim xlApp As Object = CreateObject("Excel.Application")
    'do some work with Excel
    'close any open files
    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd
    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0
    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)
    'get the process
    Dim xproc As Process = Process.GetProcessById(ProcIdXL)
    'Quit Excel
    xlApp.quit()
    'Release
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp)
    'set to nothing
    xlApp = Nothing
    'kill the process if still running
    If Not xproc.HasExited Then
        xproc.Kill()
    End If
End Sub

我看到很多人说扼杀这个过程是不好的,但我还没有看到任何关于原因的定性答案。特别是在确保文件关闭后,Excel已经退出,我们只会终止我们开始的确切过程。我的问题是终止Excel进程的潜在问题是什么。这会影响表现吗?它会损害Excel吗?

许多人也会说,有了好的编码,我不必扼杀这个过程。也许吧,但这并不能回答"为什么终止进程很糟糕?"在关闭文件、退出Excel并释放对象之后;为什么仅仅确保这个过程结束是件坏事?

编辑:Excel退出后实际剩下什么?如果Excel可见,它将正常退出,从视图和任务栏中消失。Excel是真的退出了还是没有退出。在我看来,Excel确实退出了,我们只有一个空的进程外壳在运行。有人能对此发表评论吗?

编辑:我很感兴趣地注意到GC(又名垃圾收集)通过GC.Collect()GC.WaitForPendingFinalizers()实际上会释放Excel退出后留下的进程外壳。这是否支持我的假设,即空的进程外壳毕竟是垃圾?

编辑:刚刚发现了一个关于这个问题的优秀网站:杀死Excel 的50种方法

为什么终止Excel进程是件坏事

看,事实是,如果可能的话,你应该总是让应用程序正常退出。杀死应用程序是最后的手段。我知道你确信在这种情况下做这件事没有什么错,也许你是对的。即使杀死它绝对不会对你的系统产生负面影响,但这并不能改变这样一个事实,即这样做是错误的。这就像违法,因为你知道自己不会被抓住,而且无论如何,这都是一种没有受害者的犯罪。

然而,你可能没有意识到潜在的副作用。例如,当你强制终止一个应用程序时,操作系统可能会保留它的崩溃数据。或者它可能会向微软发送崩溃遥测。你本质上是在告诉微软,应用程序崩溃的频率比实际情况更高,导致它们的崩溃统计数据略有偏差。

另一个可能的副作用是注册表配置单元可能无法正确卸载。您可能不时在事件日志中看到此错误。通常情况下,当应用程序被强制关闭,而它没有正确关闭注册表的句柄时,就会发生这种情况。

即使这些事情都没有发生,你也不知道未来版本的操作系统会做什么。今天有效的,明天可能不起作用。这就是为什么你应该始终遵循API的文档和指南,因为它们通常会非常努力地支持他们发布的内容,但通常不会非常努力地支撑他们特别告诉你不要做的内容。

当您使用自动化从另一个应用程序控制Office应用程序时,您偶尔不得不像您那样终止Office进程,以避免"泄漏"不可见的Office应用程序。这是一个不幸的结果,因为Office应用程序既试图充当最终用户应用程序,又试图充当自动化服务器。

在服务器端使用Word时,我采用了与您大致相同的解决方案(不要问为什么)。无论我们花多少精力来正确关闭Word,服务器上都会积累越来越多的"无形"Word进程。唯一好的解决方案是杀死那些在被指示退出后不会终止的进程。

当Windows进程被终止时,该进程使用的所有资源都会被操作系统清理,例如文件和其他操作系统句柄(如注册表句柄)会被关闭,内存会被释放等。从操作系统的角度来看,进程终止时不会泄露任何信息。

但是,应用程序可能会创建临时文件,以便在正常关闭期间删除这些文件。随着时间的推移,这些孤立文件可能会占用越来越多的磁盘空间。此外,如果用户在应用程序中打开了其他文件,则当进程终止时,这些文件可能会处于不一致的状态,并且可能会丢失未保存的更改。基本上,被杀死的应用程序可能"泄漏"的是它打算在关闭时清理或删除的文件。"泄漏"的另一个来源是在网络上获取的资源(例如,在共享上打开的文件)。但是,当进程终止时,网络句柄最终将变得"过时",并由网络服务器回收。

此外,我想指出的是,如果进程被终止,Watson博士将不会收集任何崩溃转储数据。只有当进程意外崩溃时才会发生这种情况(例如,出现未处理的异常)。

底线是:如果你小心的话,杀死Excel可能是避免随着时间的推移"泄露"不可见的Excel进程的最佳方法。让它们使用越来越多的系统资源运行直到系统重新启动的替代方案是不可行的。如果有的话,成本应该只不过是临时文件夹中留下的一些小文件。


作为自动化Office的替代方案,您可以使用Open XML SDK打开和修改Office文件。最初,它可能会稍微复杂一些,但在这个过程中,您可以完全避免让繁重的Office应用程序陷入困境。

根据我的经验,程序在关闭时会做一些事情:

  1. 释放所有内存引用
  2. 删除任何临时文件或工作文件
  3. 保存任何状态数据

由于这些原因,使用app.Quit()以API描述的方式关闭Excel是关键。此示例偏离规范的地方是API没有释放所有COM对象。这导致步骤1)不完整。没有办法确保应用程序在所有情况下都能有效关闭,因为您可能并不总是能够控制创建哪些COM对象。

我发现使用Excel(以及其他办公程序)的最佳方法是使用以下过程:

  1. 获取名称为Excel的进程ID列表
  2. 打开Excel
  3. 重复步骤1。使用此选项可确定您创建的新Excel实例的进程ID
  4. 使用Excel
  5. 退出Excel,释放所有创建的对象,并以Application.Quit()终止
  6. 终止进程

这使Excel有机会在进程终止前释放任何对象、删除任何临时文件和保存任何状态数据。我通常创建一个singleton类,负责管理excel实例。它实现IDisposable,在Disposal时,它将退出所有剩余的Excel应用程序。