PowerShell 使用大量内存解压缩 GZip 管道

PowerShell Decompress GZip Pipe using lots of memory

我正在编写一个 powershell Cmdlet 来接受对 gzip 文件的文件引用列表并解压缩它们并将它们的文本行放在管道上。我有一些功能正常,但它正在使用大量内存。有趣的是,完成后,如果我 运行 [System.GC]::Collect() 在 powershell 提示符下,它将释放内存。我在循环中尝试 运行ning 它,但它影响了性能。有人可以指出我做错了什么。我认为使用管道的好处之一是节省内存。即使我向它传递单个文件引用,它也会使用比文件大小更多的内存。

这是我的代码。

<#
.SYNOPSIS
Accepts GZip files piped in and outputs decrompessed text to the pipe.

.DESCRIPTION
You can use this function to pipe a list of serveral gzipped files.  They will then be decompress and concatenated
and the text will be written to the output where it can be piped to another function.

.PARAMETER PipedFile
A list of gzipped file references.

.EXAMPLE
Get-ChildItem "*.gz" | Decompress-Gzip

#>
Function Decompress-GZip {
    Param(
      [Parameter(ValueFromPipeline=$true)]
      [System.IO.FileInfo]$PipedFile

    )

    Process {

        If ( $PipedFile.Exists -eq $False) {
          Write-Host "File $PipedFile does not exist. Skipping."
          return
        }

        $BUFFER_SIZE = 65536

        $infile = $PipedFile.FullName


        $inputfile = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
        $gzipStream = New-Object System.IO.Compression.GzipStream $inputfile, ([IO.Compression.CompressionMode]::Decompress)
        try {
            $buffer = New-Object byte[]($BUFFER_SIZE)

            While (($read = $gzipstream.Read($buffer, 0, $BUFFER_SIZE)) -gt 0) {
                $str = [System.Text.Encoding]::ASCII.GetString($buffer,0,$read)
                $temp = $str -split "`r`n"
                if ($temp.Length -gt 0) {
                    if ($lastLine) {
                        $temp[0] = $lastLine + $temp[0]
                    }
                    if ($temp.Length -gt 1) {
                        Write-Output $temp[0..($temp.Length-2)]
                    }
                    $lastLine = $temp[($temp.Length-1)]
                }
            }
        } finally {
         $gzipStream.Close()
         $inputfile.Close()
        }

    }

}

OP 中的问题似乎是:"What am I doing wrong?"。

我不认为有什么必然是错误的。正如 OP 所述,发生 GC 后内存 returns 恢复正常。除非脚本或系统的其余部分存在性能问题,否则我没有理由说存在问题。

OP不够具体,不知道:1.内存使用是否与缓冲区大小有关? 2. 还是跟文件大小有关?如果文件大小在 65K 左右,则很难确定。

假设内存使用与缓冲区的大小有关,那么当查看副本时,为什么内存是缓冲区大小的几倍就很清楚了。 1. 由于 GetString 制作了一份副本。 2. 由于 -split 而制作的另一个。 3. 另一项归因于 $tempWrite-Output。 4. 根据 System.IO.Compression.GzipStreamSystem.IO.FileStream 的实现,它们可能各自有自己的未知大小的缓冲区。所以这至少是 4X 65K。