更新: PowerShell 5 似乎解决了以下错误。错误仍然存在于 3 和 4 中。因此,除非您正在运行 PowerShell 2 或5.
考虑以下代码片段:
function Get-DummyData() {
for ($i = 0; $i -lt 10000000; $i++) {
"This is freaking huge!! I'm a ninja! More words, yay!"
}
}
Get-DummyData | Out-Null
这将导致 PowerShell 内存使用量无法控制地增长。执行 Get-DummyData | 后Out-Null
几次,我看到 PowerShell 内存使用量一直高达 4 GB。
根据 ANTS Memory Profiler ,我们在垃圾收集器的终结队列中有很多东西。当我调用 [GC]::Collect()
时,内存从 4 GB 变为仅 70 MB。所以严格来说,我们没有内存泄漏。
现在,当我完成一个长期存在的管道操作时,能够调用 [GC]::Collect()
对我来说还不够好。我需要在管道操作期间进行垃圾收集。但是,如果我尝试在管道执行时调用 [GC]::Collect()
...
function Get-DummyData() {
for ($i = 0; $i -lt 10000000; $i++) {
"This is freaking huge!! I'm a ninja! More words, yay!"
if ($i % 1000000 -eq 0) {
Write-Host "Prompting a garbage collection..."
[GC]::Collect()
}
}
}
Get-DummyData | Out-Null
...问题仍然存在。内存使用量再次无法控制地增长。我尝试了几种变体,例如添加 [GC]::WaitForPendingFinalizers()
、Start-Sleep -Seconds 10
等。我尝试更改垃圾收集器 latency modes并强制 PowerShell 使用 server garbage collection 无济于事。我只是无法让垃圾收集器在管道执行时完成它的工作。
这在 PowerShell 2.0 中根本不是问题。值得注意的是,$null = Get-DummyData
似乎也可以在没有内存问题的情况下工作。所以它似乎与管道有关,而不是我们生成大量字符串这一事实。
如何防止我的内存在长管道期间不受控制地增长?
旁注:
我的 Get-DummyData 函数仅用于演示目的。我的实际问题是我无法使用 Get-Content
或 Import-Csv
在 PowerShell 中读取大文件。不,我不将这些文件的内容存储在变量中。我应该是 strictly using the pipeline。 获取内容 .\super-huge-file.txt | Out-Null
产生同样的问题。
最佳答案
这里有几点需要指出。首先,GC 调用确实在管道中工作。这是一个只调用 GC 的管道脚本:
1..10 | Foreach {[System.GC]::Collect()}
这是脚本运行期间 GC 的性能图:
但是,仅仅因为您调用了 GC,并不意味着私有(private)内存使用量将恢复到您在脚本启动之前的值。 GC 收集只会收集不再使用的内存。如果有对对象的根引用,则它没有资格被收集(释放)。因此,虽然 GC 系统通常不会在 C/C++ 意义上泄漏,但它们可能拥有比它们应有的更长的时间持有对象的内存囤积。
在使用内存分析器查看这一点时,似乎大部分多余的内存都被带有参数绑定(bind)信息的字符串副本占用了:
这些字符串的根如下所示:
我想知道是否有一些日志记录功能导致 PowerShell 卡在字符串化的表单管道绑定(bind)对象上?
顺便说一句,在这种特定情况下,分配给 $null 以忽略输出的内存效率要高得多:
$null = GetDummyData
此外,如果您需要简单地编辑文件,请查看 PowerShell Community Extensions 中的 Edit-File
命令。 3.2.0。只要您不使用 SingleString 开关参数,它就应该是内存高效的。
关于powershell - PowerShell 管道正在执行时没有垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31620763/