Powershell管道导致内存使用爆炸性增长

Powershell管道导致内存使用爆炸性增长,powershell,batch-file,Powershell,Batch File,我目前正在Powershell中编写一个脚本,允许将SVN存储库中的文件夹复制到另一个文件夹,同时保留历史记录。此类命令的一个示例是: svnadmin.exe dump $FromRepoPath ` | svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops $Folder ` | svnadmin.exe load --ignore-uuid $ToRepoPath 这

我目前正在Powershell中编写一个脚本,允许将SVN存储库中的文件夹复制到另一个文件夹,同时保留历史记录。此类命令的一个示例是:

svnadmin.exe dump $FromRepoPath `
    | svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops $Folder `
    | svnadmin.exe load --ignore-uuid $ToRepoPath
这会导致Powershell中的内存使用率非常高。Powershell似乎首先执行svnadmin.exe并缓冲来自SVN admin的标准输出,然后执行输出的svndumpfilter和缓冲区,最后执行svnadmin.exe

我可以通过创建单独的批处理文件来解决此问题:

@echo off
svnadmin.exe dump %1 | svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops %2 | svnadmin.exe load --ignore-uuid %3
然后从Powershell调用它:

cmd.exe /c "SvnHelper.cmd $FromRepoPath $Folder $ToRepoPath"
但这感觉像是一个讨厌的、不必要的解决办法


有没有办法告诉Powershell在管道传输时直接通过而不是缓冲它?

缓冲的不是输出,而是任何外部进程的输入。您可以使用如下函数验证行为:

function Read-Pipeline {
[cmdletbinding()]
param ([Parameter(Mandatory = $true, ValueFromPipeline=$true)] $inp)
    Begin {}
    Process {Write-Verbose $inp ; Return $inp}
    End {}
}
如果您随后运行:

.\LongRunning.exe | Read-Pipeline -Verbose | .\Other.exe
您将在Verbose中看到LongRunning.exe的输出,但Other.exe在其管道关闭之前不会运行。如果您这样做:

.\LongRunning.exe | Read-Pipeline -Verbose | Write-Host
您将看到无缓冲的交替冗余/控制台输出行,因为输入没有跨越进程边界

这些都没有真正帮助你。您可以通过返回到.NET来启动进程并手动将STDOUT复制到STDIN[1]来解决这个问题,但这是一项不费吹灰之力的工作。最简单的方法是将命令传递给CMD,例如:

& cmd.exe "/C svnadmin.exe dump $FromRepoPath ^| svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops $Folder ^| svnadmin.exe load --ignore-uuid $ToRepoPath

[1]

试试
svnadmin.exe…|输出字符串| svnfilter.exe…
?这可能会说服powershell对每条管线进行管道连接,而不是收集所有内容。我没有SVN,也不知道它,所以如果它坏得很厉害,我道歉。谢谢,这正是我所担心的。在您的示例中“|^”有什么作用?^|转义|字符,这是必需的,因为它是作为参数传递给cmd.exe的。