有关如何发布 (Excel) COM 对象的一般指导,请参阅底部部分。
$excel.Quit() 足以最终终止 Excel 进程,但何时发生取决于何时垃圾收集器恰好在下次运行。
您尝试使用 [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) 显式释放 Excel 是不充分的,因为变量 $script:workbook 和 $script:ws1 仍然具有对 Excel COM 对象的引用,直到变量消失后才会释放范围和这些引用最终被垃圾收集。
因此,为了加速释放,您也必须显式释放这些引用,在运行垃圾收集器之前:
$script:excel = new-object -ComObject excel.application # create excel object
$script:workbook = $excel.Workbooks.Add() # add a workbook
$script:ws1 = $workbook.Worksheets.Item(1) # reference the 1st sheet
# ...
# You must *always* call .Quit(), otherwise the Excel process lingers
# for the entire OS users session.
$script.excel.Quit()
# Relinquish references to *all* Excel objects.
$script:excel = $script:workbook = $script:ws1 = $null
# Alternative:
# Remove-Variable -Scope Script excel, workbook, ws1
# With all references released, running the garbage collector
# should now release the COM objects and terminate Excel
# at shortly after.
[GC]::Collect()
# Note that calling [GC]::WaitForPendingFinalizers() afterwards
# to wait for *completion* of the *doesn't work here*,
# because the CLR-managed RCWs (Runtime-Callable Wrappers for COM objects)
# do not guarantee deterministic release of the underlying COM objects.
因为手动清除/删除所有相关变量容易出错且很麻烦,您可以通过在临时子范围内创建所有本地引用 COM 对象的变量来自动化该过程,使用& { ... }:
& { # Create a temporary child scope.
$excel = new-object -ComObject excel.application # create excel object
$workbook = $excel.Workbooks.Add() # add a workbook
$ws1 = $workbook.Worksheets.Item(1) # reference the 1st sheet
# You must *always* call .Quit(), otherwise the Excel process lingers
# for the entire OS users session.
$excel.Quit()
} # On exiting this block, $excel, $workbook, and $ws1
# go out of scope and release the COM objects when the
# garbage collector runs next.
# Run the garbage collector now.
# The Excel process should terminate shortly after.
[GC]::Collect()
释放 (Excel) COM 对象:
-
总是调用.Quit() - 没有它,在后台创建的 Excel 进程永远不会终止,即使 PowerShell 会话结束也不会终止(当然,它会在操作系统用户终止时终止)整个会话结束)。
-
$excel.Quit() 通常是 all 需要的(除非 global 变量变量用于存储对 Excel 对象的引用),因为使用引用 COM 对象的脚本/函数变量超出范围,底层的 COM 对象最终也会自动释放。
- 但是,Excel 进程可能需要一个变化的、不可预测的时间才能真正终止,具体取决于超出范围的变量何时是对象垃圾收集。
-
如果您希望尽快释放 COM 对象:
-
您必须释放对您存储在单个变量中的所有 COM 对象的引用:
- 请注意,不需要
[System.Runtime.InteropServices.Marshal]::ReleaseComObject() 调用;因为有一个更简单且更强大的替代方案:
- 或者:清除所有显式引用 COM 对象的变量,通过(参见上面的第一个代码 sn-p):
- 或者:将它们全部设置为
$null。
- 或者:将他们的名字传递给
Remove-Variable
-
或者,最好:隐式释放引用(参见上面的第二个代码 sn-p):
-
使用通过
& { ... } 块在子范围中引用 COM 对象的变量,这意味着在离开子范围时将隐式释放引用。
-
这些方法不仅比调用[System.Runtime.InteropServices.Marshal]::ReleaseComObject() 更简单、更简洁,而且还可以防止以后尝试访问已发布的 COM 对象。
-
之后,调用[GC]::Collect() 强制进行即时垃圾收集 - 但请注意,您的代码在垃圾收集器运行时被阻塞(尽管通常只是短暂的)。
-
如果您另外想在继续之前确保释放 COM 对象已完成: