完成后PowerShell清除内存

时间:2016-11-02 18:41:29

标签: powershell memory streamreader streamwriter

我有PowerShell script读取大型CSV文件(4GB +),查找某些行,然后将这些行写入其他文件。

我注意到,当它到达" echo"在$ datafile文件中处理$ datacounter总行时#34;"脚本的最后一行,直到5-10分钟后才真正完成。

那段时间做了什么?完成后,内存使用率会大幅下降。有没有办法强制它在脚本结束时清除内存?

Screenshot of Memory Usage

Screenshot of script timestamps

以下是我的脚本的最终版本供参考。



    # Get the filename
    $datafile = Read-Host "Filename"
    $dayofweek = Read-Host "Day of week (IE 1 = Monday, 2 = Tuesday..)"
    $campaignWriters = @{}


    # Create campaign ID hash table
    $campaignByID = @{}
    foreach($c in (Import-Csv 'campaigns.txt' -Delimiter '|')) {
        foreach($id in ($c.CampaignID -split ' ')) {
            $campaignByID[$id] = $c.CampaignName
        }

        foreach($cname in ($c.CampaignName)) {
            $writer = $campaignWriters[$cname] = New-Object IO.StreamWriter($dayofweek + $cname + '_filtered.txt')
            if($dayofweek -eq 1) {
                $writer.WriteLine("ID1|ID2|ID3|ID4|ID5|ID6|Time|Time-UTC-Sec")
            }
        }
    }

    # Display the campaigns
    $campaignByID.GetEnumerator() | Sort-Object Value 

    # Read in data file
    $encoding = [Text.Encoding]::GetEncoding('iso-8859-1')
    $datareader = New-Object IO.StreamReader($datafile, $encoding)
    $datacounter = 0

    echo "Starting.."
    get-date -Format g

    while (!$datareader.EndOfStream) {
        $data = $datareader.ReadLine().Split('þ')

        # Find the Campaign in the hashtable
        $campaignName = $campaignByID[$data[3]] 
        if($campaignName) {
            $writer = $campaignWriters[$campaignName]
            # If a campaign name was returned from the hash, add the line using that campaign's writer
            $writer.WriteLine(($data[20,3,5,8,12,14,0,19] -join '|'))
        }
        $datacounter++;
    }

    $datareader.Close()
    foreach ($writer in $campaignWriters.Values) {
        $writer.Close()
    }

    echo "Done!"
    get-date -Format g
    echo "Processed $datacounter total lines in the $datafile file"

2 个答案:

答案 0 :(得分:0)

它可能会也可能不会起作用,但您可以尝试告诉垃圾收集运行:

std::

你没有对它进行细粒度的控制,在运行它之前,它可能有助于[System.GC]::Collect() 或将变量设置为Remove-Variable以便不存在对数据的引用了。

答案 1 :(得分:0)

我假设campaigns.txt是您所指的多GB文件。如果它是其他文件,这可能没有多大意义。

如果是这样,调用内部括号import-csv然后使用foreach语句迭代它们是什么驱使你的内存使用率如此之高。更好的选择是使用PowerShell管道从文件中流式传输记录,而无需同时将所有记录保存在内存中。您可以通过将foreach语句更改为ForEach-Object cmdlet:

来实现此目的
  Import-Csv 'campaigns.txt' -Delimiter '|' | ForEach-Object {
        foreach($id in ($_.CampaignID -split ' ')) {
            $campaignByID[$id] = $_.CampaignName
        }
   }

.NET垃圾收集器是优化的情况,其中大多数对象都是短暂的。因此,这种变化应该会导致显着的性能提升,并最终减少停机时间。

我建议反对强制使用[System.GC]::Collect()进行垃圾回收,垃圾回收器最好知道它应该运行的时间。原因很复杂,如果你真的想知道为什么会这样,Maoni's blog有很多关于.NET环境中垃圾收集的细节。