Stringの連結時のOutOfMemoryExceptionを回避する方法


VB.netでのWindowsアプリケーション開発をしています。  
String文字列の連結においてOutOfMemoryExceptionのエラーがスローされます。

手法としてはSingleの数値をカンマで区切り、1000個のカンマ区切り文字列を作成します。  
その文字列は「temp_Str as String」の変数に格納していくのですが、  
大型のループ処理で10万件以上作成されたところで上記のエラーが発生します。  
（時間にして2～3時間程度経過した時点）

少なくとも数100万件の処理を行いたいのですが、  
うまくメモリー管理をする方法はないでしょうか？  
今現在GC.CollectやRemove等の処理は入れているのですが、あまり効果がありません。  
よろしくお願いいたします。




「String文字列の連結にはStringBuilderを使うのがいいですよ」と回答を書こうとしてコード例を作ったところ、件数が多すぎてStringBuilderを使ってもOutofMemoryExceptionが出てしまいました。

件数が多くてメモリ上で全件を処理できない場合、行ごとに処理をするよう発想を変えるのがベターだと思います。

この方法なら数100万件を超えても、ディスク容量の許す限りエラーにはなりません。  
※分散処理でDBにでも格納するのがベストかもしれませんが、環境のセットアップなどが必要になるためここでは扱いません。

以下は `C:\tmp123456789.txt` というファイルを一時的に書き出して、各行ごとに処理してからファイルを消すサンプルコードです。  
手元の環境では1万行に対して30秒ほどで出力が、80秒ほどで全体の処理が終わりました。

[code]

    Imports System.IO
    
    Module Module1
    
        Sub Main()
            Dim tmpFile = "C:\tmp123456789.txt" 
    
            Dim stopwatch As New Stopwatch
            stopwatch.Start()
    
            Dim rnd As Random = New Random
            '件数が多いのでStringBuilderでもメモリ不足
            'Dim sb As StringBuilder = New StringBuilder
            'ファイルを開いておいて逐次出力
            Dim writer As New StreamWriter(tmpFile, False)
            'ある程度データがたまったら自動書き出しするモード
            writer.AutoFlush = True
    
            '10の5乗 = 10,000
            For i = 1 To Math.Pow(10, 5)
                Dim list As List(Of Single) = New List(Of Single)
                '行データ作成
                For j = 1 To 1000
                    list.Add(CType(rnd.NextDouble(), Single))
                Next
                '行データ出力(全件データを一気に扱う必要がなければ、StreamWriterを使わずにここで各行の処理をしてもいいです)
                writer.WriteLine(String.Join(",", list))
            Next
            writer.Close()
            Dim msg1 = String.Format("テンポラリファイル作成時間: {0} 秒", stopwatch.ElapsedMilliseconds / 1000)
            Console.WriteLine(msg1)
            'ファイル出力が目的ならここでおしまい。
    
            'テンポラリファイルの各行を読み出しながら処理
            Dim total As Double = 0
            Dim reader As New StreamReader(tmpFile)
    
            ' 読み込みできる文字がなくなるまで繰り返す
            While (Not reader.EndOfStream)
                ' ファイルを 1 行ずつ読み込む
                Dim line = reader.ReadLine
                '何か処理する(ここではサンプルとして加算している)
                For Each s In line.Split(",")
                    total += Single.Parse(s)
                Next
            End While
            reader.Close()
            '後始末
            File.Delete(tmpFile)
    
            Dim msg2 = String.Format("処理完了時間: {0} 秒", stopwatch.ElapsedMilliseconds / 1000)
            Console.WriteLine(msg2)
            Console.WriteLine("合計値は {0} です。", total)
            Console.ReadLine()
        End Sub
    
    End Module
    
[/code]

