挥之不去的 Excel 进程

Lingering Excel Process

我正在做一个 Windows 服务,我正在使用 Microsoft.Office.Interop.Excel 创建一个新的 excel 文件,编辑它,然后保存它。

完成后,关闭相应的对象(工作表、工作簿),退出 excel 应用程序,并 Marshal 释放 COM 对象,这个过程仍然存在。

    private void doWork()
    {
        var excelApp = new MsExcel.Application();
        var workBooks = excelApp.Workbooks;
        var workbook = excelApp.Workbooks.Add();
        var sheets = workbook.Sheets;
        _worksheet = workbook.Sheets[1];

        //Do Work Here

        _worksheet.SaveAs(filePath);
        workbook.Close(false,System.Reflection.Missing.Value,System.Reflection.Missing.Value);
        workBooks.Close();
        releaseObject(_worksheet);
        releaseObject(sheets);
        releaseObject(workbook);
        releaseObject(workBooks);
        excelApp.Quit();
        releaseObject(excelApp);

    }

    private void releaseObject(object obj)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            _log.Error($"Unable to release object {obj} Error:" + ex.ToString());
            obj = null;
        }
        finally
        {
            GC.Collect();
        }
    }

我看到其他一些建议释放对象的帖子,以及对 Workbooks 和 Sheets 的引用。不确定,为什么这仍然不起作用。

Microsoft 目前不推荐也不支持来自任何无人值守、非交互式客户端应用程序或组件(包括 ASP、ASP.NET、DCOM 和 NT)的 Microsoft Office 应用程序自动化服务),因为当 Office 在此环境中 运行 时,Office 可能表现出不稳定的行为 and/or 死锁。

如果您正在构建 运行 在服务器端上下文中的解决方案,您应该尝试使用已针对无人值守执行安全设置的组件。或者,您应该尝试找到至少允许 运行 客户端部分代码的替代方案。如果您从服务器端解决方案使用 Office 应用程序,该应用程序将缺少许多 运行 成功所必需的功能。此外,您将承担整体解决方案稳定性的风险。在 Considerations for server-side Automation of Office 文章中阅读更多相关信息。

作为解决方法,您可以考虑使用 One XML SDK 或为服务器端或服务执行设计的任何其他第三方组件。

您不应该调用 ReleaseComObject。那是很久以前就开始的老太太故事了,但是 it is incorrect

如果您看到 excel 个实例仍然存在,这可能意味着您的程序在没有 运行 垃圾收集器和仍然保留到 com 对象的引用的情况下终止。解决问题的最佳方法是完全摆脱释放功能,然后在 doWork() 方法 returns.

之后调用 GC.Collect()
private void doWork()
{
    try
    {
        doWorkImpl();
    }
    finally
    {
        GC.Collect(); //The GC collect needs to be here, after the scope of doWorkImpl ends.
        GC.WaitForPendingFinalizers(); //The excel instance gets closedin the finalizer.
    }
}

private void doWorkImpl()
{
    var excelApp = new MsExcel.Application();
    var workBooks = excelApp.Workbooks;
    var workbook = excelApp.Workbooks.Add();
    var worksheet = workbook.Sheets[1]; //This needs to be a local variable, not a class variable.

    //Do Work Here

    worksheet.SaveAs(filePath);
    workbook.Close(false,System.Reflection.Missing.Value,System.Reflection.Missing.Value);
    workBooks.Close();
    excelApp.Quit();

}

这应该会导致 excel 实例运行,只要没有抛出异常并且 excelApp.Quit() 被成功调用。

但是,如果您只使用 xlsx 文件而不是 xsl 文件,我会 高度 建议远离 com 互操作和只需使用 the SDK microsoft provides 直接与 .xlsx 文件交互。