2016-11-02 11 views
0

大きなCSVファイル(4GB +)を読み取り、特定の行を見つけて、その行を他のファイルに書き込むPowerShell scriptがあります。終了後のPowerShellメモリの消去

スクリプトの最後の行である$ datafileファイルの "$ echo"処理された$ datacounter行が気になるのですが、実際には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" 

+0

最後の行が完了するまでスクリプトは実際には実行されません。 "done:$(get-date -Format g)"を使用して、正確に起こるか確認してください – Jimbo

答えて

0

これは、または動作しない場合がありますが、あなたは実行するために、ガベージコレクションを伝えるために試すことができます:

[System.GC]::Collect() 

あなたはしかし、それ以上のきめの細かい制御を持っていない、それはRemove-Variableに役立つかもしれません実行する前に変数を$nullに設定して、データへの参照がなくなるようにしてください。

0

campaigns.txtは、あなたが参照しているマルチギガバイトのファイルであると仮定しています。それが他のファイルの場合、これはあまり意味がないかもしれません。

もしそうなら、import-csvの中括弧を呼び出して、foreachステートメントを使って反復処理すると、メモリ使用量がそれほど高くなりません。より良い選択肢は、PowerShellパイプラインを使用して、それらをすべて同時にメモリに保存する必要なく、ファイルからレコードをストリーミングすることです。あなたはForEach-Objectコマンドレットにforeachなステートメントを変更することでこれを実現:

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

.NETガベージコレクタは、オブジェクトの大半が短命ある場合に最適化されています。そのため、この変更により、パフォーマンスが大幅に向上するだけでなく、最後に終了時間が短縮されます。

に対してを強制的に実行してガベージコレクションを[System.GC]::Collect()とすると、ガベージコレクタは実行時に最もよく分かります。この理由は複雑です。なぜこれが本当であるかの詳細を知りたければ、Maoni's blogには.NET環境でのガベージコレクションに関する豊富な詳細があります。

+0

ガベージコレクションに関する情報をありがとう。マルチGBファイルは、実際にはStreamReaderによって読み取られている '$ datafile 'です。 'campaigns.txt'ファイルは非常に小さく、10行しかありません。 – Esuriency

関連する問題