有关如何释放 (Excel) COM 对象的一般指导,请参阅底部部分。
$excel.Quit()
足以最终终止Excel 进程,但何时发生取决于垃圾收集器下一次运行的时间。
您尝试显式释放 Excel[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
是不够的,因为变量仍然具有对 Excel COM 对象的引用,这些对象$script:workbook
在$script:ws1
变量超出范围之前不会被释放,并且这些引用最终会被垃圾回收。
因此,为了加快释放速度,您必须在运行垃圾收集器之前也显式释放这些引用:
$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()
通常只需要这些(除非全局变量变量用于存储对 Excel 对象的引用),因为引用 COM 对象的脚本/函数变量超出范围,最终也会自动释放底层 COM 对象。
- 但是,Excel 进程实际终止可能需要一个不同的、不可预测的时间,具体取决于何时对超出范围的变量进行垃圾收集的对象。
如果您希望尽快释放 COM对象:
您必须释放对存储在单个变量中的所有COM 对象的引用:
- 请注意,不需要
[System.Runtime.InteropServices.Marshal]::ReleaseComObject()
调用;因为有一个更简单、更强大的替代方案:
- 要么:通过(参见上面的第一个代码片段)
明确地清除所有引用 COM 对象的变量:
- 要么:将它们全部设置为
$null
.
- 或:将他们的名字传递给
Remove-Variable
- 或者,最好:隐式释放引用(参见上面的第二个代码片段):
- 使用通过块引用子作用域中的 COM 对象的变量
& { ... }
,这意味着在离开子作用域时将隐式释放引用。
这些方法不仅比调用更简单、更简洁[System.Runtime.InteropServices.Marshal]::ReleaseComObject()
,而且还可以防止以后尝试访问已发布的 COM 对象。
之后,调用[GC]::Collect()
强制即时垃圾收集 - 但请注意,当垃圾收集器运行时您的代码被阻塞(尽管通常只是短暂的)。
如果您还想确保在继续之前释放 COM 对象已完成: