PowerShell管道执行时无垃圾收集

PowerShell管道执行时无垃圾收集,powershell,memory,garbage-collection,powershell-3.0,Powershell,Memory,Garbage Collection,Powershell 3.0,更新:以下错误似乎已通过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-Nul

更新:以下错误似乎已通过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

据我们所知,在垃圾收集器的终结队列中有很多东西。当我调用
[GC]::Collect()
时,内存从4GB变为70MB。严格来说,我们没有内存泄漏

现在,当我完成一个长期的管道操作时,我还不能调用
[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()
启动睡眠-10秒
,等等。我尝试更改垃圾收集器并强制PowerShell使用,但都没有用。我就是不能让垃圾收集器在管道执行时完成它的工作

这在PowerShell 2.0中根本不是问题。还值得注意的是,
$null=Get-DummyData
似乎也可以在没有内存问题的情况下工作。因此,它似乎与管道有关,而不是我们正在生成大量字符串的事实

我怎样才能防止我的记忆在漫长的管道中失控地增长

旁注:


我的Get DummyData函数仅用于演示目的。我的现实问题是,我无法使用
Get Content
Import Csv
读取PowerShell中的大型文件。不,我没有将这些文件的内容存储在变量中。我就像我应该做的那样<代码>获取内容。\super-maging-file.txt | Out Null也会产生同样的问题。

在处理大量文本文件等异常操作时,发现本机cmdlet不能完全满足您的要求并不少见。就我个人而言,我发现在Powershell中使用System.IO编写脚本时,在Powershell中处理大文件会更好。StreamReader:

$SR = New-Object -TypeName System.IO.StreamReader -ArgumentList 'C:\super-huge-file.txt';
while ($line = $SR.ReadLine()) {
    Do-Stuff $line;
}
$SR.Close() | Out-Null;
请注意,您应该使用ArgumentList中的绝对路径。对我来说,它似乎总是假设你在你的主目录与相对路径

Get Content
只是将整个对象作为数组读入内存,然后输出。我想它只是调用System.IO.File.ReadAllLines()

我不知道有什么方法可以告诉Powershell在完成后立即丢弃管道中的项,或者函数可以异步返回项,因此它会保留顺序。它可能不允许这样做,因为它无法自然地判断对象以后不会使用,或者以后的对象不需要引用以前的对象


Powershell的另一个优点是,您也可以经常使用它。我从未尝试过,但这看起来也很容易使用。

这里有几点需要指出。首先,GC调用在管道中工作。下面是一个仅调用GC的管道脚本:

1..10 | Foreach {[System.GC]::Collect()}
以下是脚本运行期间GCs的性能图:

然而,仅仅因为您调用了GC,并不意味着私有内存使用将返回到脚本启动之前的值。GC collect将只收集不再使用的内存。如果存在对对象的根引用,则不符合收集(释放)的条件。因此,虽然GC系统通常不会在C/C++意义上泄漏,但它们可能会有内存囤积,这些内存囤积在对象上的时间可能比它们应该的要长

在使用内存分析器查看这一点时,似乎多余内存的大部分被带有参数绑定信息的字符串的副本占用:

这些字符串的根如下所示:

我想知道是否有一些日志功能导致PowerShell挂起字符串化的表单管道绑定对象

顺便说一句,在这种特定情况下,将$null赋值以忽略输出会更节省内存:

$null = GetDummyData

此外,如果您只需要编辑文件,请查看3.2.0中的
编辑文件
命令。只要不使用SingleString开关参数,它应该是内存有效的。

听起来有点像。内存耗尽部分听起来像个bug。通过使用assignment避免管道化/枚举1000万个对象,可以显著减少CPU时间,强制转换或属性枚举我无法重现所提供的代码段的问题。@RomanKuzmin是否使用PowerShell 2.0?在V4和V5 build 5.0.10240.16384上执行第二个示例期间,我发现内存使用量超过2 GB。即使使用StreamReader方法,事实上,您正在通过管道推动字符串导致问题。另外,我不认为Get Content返回一个简单的字符串数组。我过去曾在PowerShell 2.0中使用它来处理数百兆字节的数据,而内存使用率可以忽略不计。@Phil StreamReader方法的关键在于,您根本不使用管道。您正在逐行读取文件,而不是读取整个文件并通过管道传输内容。在我的
dostuff$line中,你正在做你需要的一切。问题是,您不能同时访问两行,性能可能会更差,因为IO可能会出现瓶颈,但作为回报,您基本上不使用内存。然而,谷歌搜索会发现很多人在获取内容时存在记忆问题
Get Content |[…]
$x=Get Content
具有不同的内存使用率,这就是