【问题标题】:High memory consumption when returning a byte array from function从函数返回字节数组时内存消耗高
【发布时间】:2019-07-07 18:34:37
【问题描述】:

我正在尝试下载一个 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:

调用上述函数结果为500MB:

如此高的内存使用率是什么原因,我可以做些什么来优化它?

Powershell 版本:

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

【问题讨论】:

  • 调用函数时不要使用方括号。相反,请使用单个空格字符。 $x = My-Download "https://..."。此外,参数位置的第一个索引是 0,而不是 1。
  • 这似乎不能解决问题。
  • (New-Object System.Net.WebClient).DownloadData($UrlCode) -> ,(New-Object System.Net.WebClient).DownloadData($UrlCode)
  • 非常感谢,成功了!逗号是什么意思,没有逗号会发生什么?
  • @hurlenko - 该位置的逗号运算符将数组包裹在右侧的项目周围。这会导致 PoSh 的“展开集合”功能展开 outer 集合,而不展开内部集合。显然,将集合分成几部分以传递是内存使用的来源。 ///// 我什至不想去研究那个... [grin]

标签: powershell


【解决方案1】:

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

  • 如果您将调用该方法的输出分配给变量直接,则变量会按原样接收该字节数组em>。

  • 相比之下,如果使用对该方法的调用从函数生成隐式输出,则[byte[]] 数组的元素逐个发送到管道(逐字节)。
    管道背后的设计意图是启用 streamingobject-by-object 处理,而不是先收集所有结果的行为,后者以执行速度换取内存限制,一个接一个,作为输出变为可用的处理。

函数的输出分配给一个变量,然后使PowerShell在一个常规的[object[]]数组中隐式收集各个输出对象(在本例中为字节)。 p>

换句话说:最初的[byte[]] 数组是第一个枚举,后来才被收集到另一个 数组中,尽管是一个[object[]] 类型的数组 - 那在您的场景中显然是不必要且效率低下的。

有两种方法可以退出此隐式枚举

  • 除了 implicit 输出,您可以使用 conceptually explicit Write-Output -NoEnumerate 调用来抑制输出数组的枚举(集合):

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

  • 一种更晦涩但更简洁、更快的替代方法是将隐式输出与辅助单元素包装器数组结合起来,这会导致 PowerShell 仅枚举包装器数组,并传递包装器数组,正如PetSerAl 在对问题的评论中所建议的那样:

  • , (New-Object System.Net.WebClient).DownloadData($UrlCode)

  • , 是 PowerShell 的数组构造运算符("comma operator"),在其 一元 形式中,它将 RHS 包装在一个单元素数组([object[]] 类型)中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 2012-05-18
    • 1970-01-01
    相关资源
    最近更新 更多