【问题标题】:PowerShell Decompress GZip Pipe using lots of memoryPowerShell 使用大量内存解压缩 GZip 管道
【发布时间】:2016-01-26 01:07:46
【问题描述】:

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

这是我的代码。

<#
.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()
        }

    }

}

【问题讨论】:

  • 看起来与stackoverflow.com/questions/34968966/… 类似,但由于您的“GC 收集”有效,所以不太一样。如果您正在处理数十个或数百个文件,也许每三个/十个左右的文件只运行一次“GC 收集”可以提高性能并降低内存使用量。

标签: powershell gzip gzipstream


【解决方案1】:

OP 中的问题似乎是:“我做错了什么?”。

我不认为有任何问题。正如 OP 所述,内存在 GC 发生后恢复正常。除非存在性能问题,无论是在脚本中还是在系统的其余部分中,我都没有理由说有问题。

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

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

【讨论】:

  • 所以,我发布此内容的原因是因为我的脚本使用 64k 缓冲区进行蒸汽处理,但是当我解压缩单个 350 mb gzip 文件时,内存不断攀升并超过 7gb。它确实在那里平稳,所以我想没关系。我只是无法想象从这段代码中创建和重新创建了什么会导致内存使用量增加这么多。
  • 知道这很有帮助,但您应该将该详细信息放在 OP 中,而不是在评论中,以便其他阅读您的问题的人很容易找到它。如果您想更深入地研究此行为,您可以使用 Windbg 和 SOS 扩展来检查堆上的对象集。有许多关于使用 SOS 的信息来源(在 SO 和网络上),但我发现最简单的方法是在 Windbg 下运行 PS。在需要时进入调试器(Ctrl-Break),然后执行.cordll -l,然后执行!sos.help 以获得帮助。我认为 !gchandles 是正确的命令。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-11
  • 1970-01-01
  • 2021-11-15
相关资源
最近更新 更多