从函数返回字节数组时的高内存消耗

时间:2019-07-07 18:34:37

标签: powershell

我正在尝试下载10MB的文件并将其存储为数组以进行进一步处理。

使用直接调用(New-Object System.Net.WebClient).DownloadData("<url>")时,一切似乎都很好。但是,如果我将其包装在函数中,然后将调用结果返回到WebClient::DownloadData,则内存占用量将增加到500mb左右。

我使用的功能:

function My-Download {
    param (
        [Parameter(Mandatory = $True, Position = 1)] [String] $UrlCode
    )
    (New-Object System.Net.WebClient).DownloadData($UrlCode)
}
$x = My-Download("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1280_10MG.mp4")

我将其包装在函数中的原因是,在返回数据之前我也对数据进行了额外的处理,但即使是这个小例子也可以说明问题。

呼叫$x = (New-Object System.Net.WebClient).DownloadData("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1280_10MG.mp4")会产生83MB的空间:

direct call memory consumption

调用上述函数将导致500MB:

wrapper function memory consumption

为何如此之高的内存使用量是什么原因,我该怎么做才能对其进行优化?

Powershell版本:

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17134  407

1 个答案:

答案 0 :(得分:1)

[System.Net.WebClient]类型的.DownloadData()方法返回字节数组([byte[]])。

  • 如果您将对该方法的调用的输出直接分配给变量 ,则变量将按以下方式接收该字节数组

  • 相反,如果使用对该方法的调用从函数 中产生隐式输出,则{{1 }} 数组的元素被一个接一个地发送到管道 (逐字节)。
    流水线背后的设计意图是启用逐个对象处理,而不是收集所有结果优先的行为,这会以执行速度为代价来限制内存,成为输出的一对一处理。

函数的输出分配给变量,然后使PowerShell 以常规[byte[]]数组隐式收集单个输出对象(在这种情况下为字节)。

换句话说:原始的[object[]]数组是首先被枚举的,直到后来被收集在另一个数组中,尽管是[byte[]]-输入一个-在您的情况下显然是不必要的并且效率低下。

两种退出此隐式枚举的方法

  • 您可以使用 概念上明确的 [object[]] 来代替隐式输出,以禁止枚举输出数组(集合):

    • Write-Output -NoEnumerate
  • 一个比较晦涩的方法,但 更简洁,更快速 的替代方法是将隐式输出与辅助单元素包装器数组< / em> ,这会导致PowerShell仅枚举包装器数组,并通过包装的数组,就像PetSerAl在对问题的评论中所建议的那样:

    • Write-Output -NoEnumerate (New-Object System.Net.WebClient).DownloadData($UrlCode)

    • , (New-Object System.Net.WebClient).DownloadData($UrlCode)是PowerShell的数组构造运算符("comma operator"),并且以其一元形式将RHS封装为单个元素({{ 1}})数组。