PowerShell:将16MB CSV导入到PowerShell变量中将创建> 600MB的PowerShell内存使用情况

戴夫·斯帕兹(Dave Spatz)

我试图理解为什么在导入一个约16MB的文件作为变量时,PowerShell的内存如此之大。我可以理解该变量周围还有其他内存结构,但我只是想了解为什么它那么高。这是我在下面做的-只是任何人都可以运行的另一个脚本的简化片段。

注释/问题

  1. 不要抱怨,要了解为什么要使用这么多的内存,是否有更好的方法做到这一点,或者可以更有效地管理内存以尊重我正在运行此系统的系统。
  2. 在PowerShell 5.1和刚刚发布的PowerShell 7,RC3中,也会发生相同的行为。我不认为这是一个错误,只是我了解更多信息的另一个机会。
  3. 我的总体目标是运行一个foreach循环,以对照该数组检查另一个更小的数组是否匹配或缺少该数组。

我的测试代码

Invoke-WebRequest -uri "http://s3.amazonaws.com/alexa-static/top-1m.csv.zip" -OutFile C:\top-1m.csv.zip

Expand-Archive -Path C:\top-1m.csv.zip -DestinationPath C:\top-1m.csv

$alexaTopMillion = Import-Csv -Path C:\top-1m.csv

对于回答此问题的任何人:谢谢您的时间,并帮助我每天学习更多!

mklement0

一般来说iRon在对该问题的评论中的建议值得关注(具体问题在此问题后面的部分中进行了阐述):

为了保持较低的内存使用率,请在流水线中使用对象而不要先将它们收集在内存中-如果可行:

也就是说,不要这样做:

# !! Collects ALL objects in memory, as an array.
$rows = Import-Csv in.csv
foreach ($row in $rows) { ... }

做这个:

# Process objects ONE BY ONE.
# As long as you stream to a *file* or some other output stream
# (as opposed to assigning to a *variable*), memory use should remain constant,
# except for temporarily held memory awaiting garbage collection.
Import-Csv in.csv | ForEach-Object { ... } # pipe to Export-Csv, for instance

但是,即使那样,您似乎仍然可以非常大的文件耗尽内存-请参见此问题-可能与尚未被垃圾回收的不再需要的对象建立内存有关;因此,周期性地调用[GC]::Collect()ForEach-Object脚本块可以解决这个问题。


如果确实需要Import-Csv 一次收集内存中所有输出的对象,执行以下操作

您观察到过度内存使用来自如何实现[pscustomobject]实例(Import-Csv的输出类型),如本GitHub问题(强调)中所述:

内存压力很可能来自PSNoteProperty[[pscustomobject]属性的实现方式]的成本每个PSNoteProperty属性都有48个字节的开销,因此,如果每个属性仅存储几个字节,则将变得很大

相同的问题提出了一种减少内存消耗解决方法(也如Wasif Hasan的答案所示):

  • 阅读CVS的第一行,并使用来动态创建一个代表这些行自定义类Invoke-Expression

    • 注意:虽然此处安全使用,Invoke-Expression但通常应避免使用

    • 如果您事先知道列结构,则可以class按常规方式创建自定义方式,这还允许您为属性使用适当的数据类型(默认情况下为所有字符串)。例如,将适当的属性定义为[int]System.Int32)可进一步减少内存消耗。

  • Import-CsvForEach-Object,其将每个呼叫[pscustomobject]创建动态创建的类,它更有效地存储数据的一个实例。

注意:此解决方法的代价是执行速度大大降低

$csvFile = 'C:\top-1m.csv'

# Dynamically define a custom class derived from the *first* row
# read from the CSV file.
# Note: While this is a legitimate use of Invoke-Expression, 
#       it should generally be avoided.
"class CsvRow { 
 $((Import-Csv $csvFile | Select-Object -first 1).psobject.properties.Name -replace '^', '[string] $$' -join ";") 
}" | Invoke-Expression

# Import all rows and convert them from [pscustomobject] instances 
# to [CsvRow] instances to reduce memory consumption.
# Note: Casting the Import-Csv call directly to [CsvRow[]] would be noticeably
#       faster, but increases *temporary* memory pressure substantially.
$alexaTopMillion = Import-Csv $csvFile | ForEach-Object { [CsvRow] $_ }

从长远来看,一个更好的解决方案(也将是更快的)是使Import-Csv支持输出具有给定输出类型的已解析行,例如通过此GitHub问题中提出-OutputType参数如果您对此感兴趣,请在此处表示您对提案的支持。


内存使用基准:

以下代码将正常Import-Csv导入([pscustomobject]s的数组)的内存使用与变通方法(自定义类实例的数组)进行比较。

测量是不精确的,因为仅查询PowerShell的进程工作内存,它可以显示后台活动的影响,但是粗略了解使用自定义类需要多少内存。

样本输出,表明自定义类的解决方法仅需要样本10列CSV输入文件的内存的大约五分之一,下面使用了大约166,000行-具体比率取决于输入行和列的数量:

MB Used Command
------- -------
 384.50  # normal import…
  80.48  # import via custom class…

基准代码:

# Create a sample CSV file with 10 columns about 16 MB in size.
$tempCsvFile = [IO.Path]::GetTempFileName()
('"Col1","Col2","Col3","Col4","Col5","Col6","Col7","Col8","Col9","Col10"' + "`n") | Set-Content -NoNewline $tempCsvFile
('"Col1Val","Col2Val","Col3Val","Col4Val","Col5Val","Col6Val","Col7Val","Col8Val","Col9Val","Col10Val"' + "`n") * 1.662e5 |
  Add-Content $tempCsvFile

try {

  { # normal import
    $all = Import-Csv $tempCsvFile
  },
  { # import via custom class
    "class CsvRow {
      $((Import-Csv $tempCsvFile | Select-Object -first 1).psobject.properties.Name -replace '^', '[string] $$' -join ";")
    }" | Invoke-Expression
    $all = Import-Csv $tempCsvFile | ForEach-Object { [CsvRow] $_ }
  } | ForEach-Object {
    [gc]::Collect(); [gc]::WaitForPendingFinalizers() # garbage-collect first.
    $before = (Get-Process -Id $PID).WorkingSet64
    # Execute the command.
    & $_
    # Measure memory consumption and output the result.
    [pscustomobject] @{
      'MB Used' = ('{0,4:N2}' -f (((Get-Process -Id $PID).WorkingSet64 - $before) / 1mb)).PadLeft(7)
      Command = $_
    }
  }

} finally {
  Remove-Item $tempCsvFile
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

PowerShell GUI csv导入到ListView

来自分类Dev

如果使用jsonArray,则导入到Mongo的限制为16MB

来自分类Dev

如果使用jsonArray,则导入到Mongo的限制为16MB

来自分类Dev

使用Powershell将CSV导入到Excel

来自分类Dev

Windows Powershell显示CPU百分比和内存使用情况

来自分类Dev

在Powershell中输出磁盘使用情况

来自分类Dev

使用PowerShell将数据正确导入到数组中

来自分类Dev

使用PowerShell将数据正确导入到阵列中

来自分类Dev

如何通过Powershell检索IAM实体限制和当前使用情况

来自分类Dev

Azure PowerShell-从所有订阅中获取VM使用情况

来自分类Dev

如何通过Powershell检索IAM实体限制和当前使用情况

来自分类Dev

获取 AzureRm 托管磁盘空间使用情况和可用空间 - Powershell

来自分类Dev

Mongodb上限为16mb:替代

来自分类Dev

Android-将堆大小限制为16MB以进行测试?

来自分类Dev

DB2将CLOB(> 16Mb)保存到IFS中

来自分类Dev

DB2将CLOB(> 16Mb)保存到IFS中

来自分类Dev

将XML文件解析到Google App Engine数据存储区时的内存使用情况

来自分类Dev

执行Office365使用情况报告的PowerShell脚本所需的用户角色是什么?

来自分类Dev

使用 Mongoose Populate 遇到 16MB BSON 限制

来自分类Dev

每个变量的R内存使用情况

来自分类Dev

每个变量的R内存使用情况

来自分类Dev

const声明的变量的内存使用情况

来自分类Dev

bacpac还原到SQL Server的内存使用情况

来自分类Dev

使用cakephp将数据从csv导入到mysql

来自分类Dev

使用Yii Framework将数据从csv导入到Mysql

来自分类Dev

使用sql将数据从文件csv导入到Oracle

来自分类Dev

使用VBA将数据从.csv导入到Excel文档

来自分类Dev

mongodb和pymongo文件大小限制为16Mb

来自分类Dev

MongoDb聚合16MB缓冲区大小限制

Related 相关文章

  1. 1

    PowerShell GUI csv导入到ListView

  2. 2

    如果使用jsonArray,则导入到Mongo的限制为16MB

  3. 3

    如果使用jsonArray,则导入到Mongo的限制为16MB

  4. 4

    使用Powershell将CSV导入到Excel

  5. 5

    Windows Powershell显示CPU百分比和内存使用情况

  6. 6

    在Powershell中输出磁盘使用情况

  7. 7

    使用PowerShell将数据正确导入到数组中

  8. 8

    使用PowerShell将数据正确导入到阵列中

  9. 9

    如何通过Powershell检索IAM实体限制和当前使用情况

  10. 10

    Azure PowerShell-从所有订阅中获取VM使用情况

  11. 11

    如何通过Powershell检索IAM实体限制和当前使用情况

  12. 12

    获取 AzureRm 托管磁盘空间使用情况和可用空间 - Powershell

  13. 13

    Mongodb上限为16mb:替代

  14. 14

    Android-将堆大小限制为16MB以进行测试?

  15. 15

    DB2将CLOB(> 16Mb)保存到IFS中

  16. 16

    DB2将CLOB(> 16Mb)保存到IFS中

  17. 17

    将XML文件解析到Google App Engine数据存储区时的内存使用情况

  18. 18

    执行Office365使用情况报告的PowerShell脚本所需的用户角色是什么?

  19. 19

    使用 Mongoose Populate 遇到 16MB BSON 限制

  20. 20

    每个变量的R内存使用情况

  21. 21

    每个变量的R内存使用情况

  22. 22

    const声明的变量的内存使用情况

  23. 23

    bacpac还原到SQL Server的内存使用情况

  24. 24

    使用cakephp将数据从csv导入到mysql

  25. 25

    使用Yii Framework将数据从csv导入到Mysql

  26. 26

    使用sql将数据从文件csv导入到Oracle

  27. 27

    使用VBA将数据从.csv导入到Excel文档

  28. 28

    mongodb和pymongo文件大小限制为16Mb

  29. 29

    MongoDb聚合16MB缓冲区大小限制

热门标签

归档