为什么杀掉Excel进程是个坏事?

时间:2013-07-22 07:03:22

标签: c# .net vb.net excel excel-interop

我已经看过很多文章和问题,关于如何确保Excel在你想要的时候实际退出并且过程不能保持活力。 Here is a knowledge Base article描述了问题和Microsoft推荐的解决方案。基本上:

'close files

'Quit Excel
xlApp.quit()

'Release and collect garbage
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp)
GC.Collect()
GC.WaitForPendingFinalizers()

许多人不建议杀死这个过程;看到 How to properly clean up Excel interop objectsUnderstanding Garbage Collection in .net

另一方面,很多人不建议使用GC.Collect。见What's so wrong about using GC.Collect()?

根据我的经验,杀死该过程是确保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实际上已经退出,我们只有一个空的进程shell运行。任何人都可以对此发表评论吗?

编辑:我很有意思通过GC.Collect()注意GC(也就是垃圾收集) GC.WaitForPendingFinalizers()实际上将释放Excel退出后留下的进程shell。这是否支持我的假设,即空进程shell真的是垃圾?

编辑:刚刚找到一个关于此问题的优秀网站:50 Ways to kill Excel

3 个答案:

答案 0 :(得分:6)

看,事实是,如果可能的话,你应该总是让应用程序正常退出。杀死应用程序是最后的选择。我知道你确信你在这种情况下没有看到任何错误,也许你是对的。即使你的系统绝对没有任何负面影响杀死它,这并不会改变这样做的事实。这就像打破了法律,因为你知道你不会被抓住,而且无论如何这都是无受害者的犯罪。

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

另一个可能的副作用是注册表配置单元可能无法正确卸载。您可能不时在事件日志中看到此错误。它通常发生在强行关闭应用程序并且没有正确关闭注册表的句柄时。

即使没有发生这些事情,您也无法知道操作系统的未来版本可能会发生什么。什么在今天有效,明天可能无效。这就是为什么你应该总是遵循所记录的API和指南,因为他们通常会非常努力地支持他们发布的内容,但通常不会非常努力地支持他们明确告知的内容。你不要这样做。

答案 1 :(得分:4)

当您使用自动化从另一个应用程序控制Office应用程序时,您偶尔必须杀死Office进程,以避免“泄漏”不可见的Office应用程序。这是Office应用程序如何尝试充当最终用户应用程序以及自动化服务器的不幸结果。

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

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

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

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

底线:如果你小心杀死Excel可能是避免随着时间的推移“泄漏”隐藏的Excel进程的最佳方法。在系统重新启动之前让它们使用越来越多的系统资源运行的替代方案是不可行的。费用(如果有的话)应该只是临时文件夹中留下的一些小文件。


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

答案 2 :(得分:0)

根据我的经验,程序在关闭时会执行一些操作:

  1. 释放所有内存引用
  2. 删除所有临时或工作文件
  3. 保存所有州数据
  4. 由于这些原因,您使用app.Quit()以API描述的方式关闭Excel 严重。如果此示例偏离Norm,则API不会释放所有COM个对象。这导致步骤1)不完整。在任何情况下都无法确保应用程序有效关闭,因为您可能无法始终控制创建的COM对象。

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

    1. 获取名称包含Excel
    2. 的进程ID列表
    3. 打开Excel
    4. 重复步骤1.使用此选项确定您创建的新Excel实例的进程ID
    5. 使用Excel
    6. 退出Excel,释放您创建的所有对象并使用Application.Quit()
    7. 终止
    8. 终止这个过程
    9. 这使Excel有机会在进程终止之前释放任何对象,删除任何临时文件并保存任何状态数据。我通常创建一个单例类,负责管理excel实例。它实现了IDisposable,在Disposal上,它将退出所有剩余的Excel应用程序。