3

RowCollectionが50000以上の場合、次の関数からメモリ不足の例外が発生するため、メモリ効率を高める必要があります。この関数は、RowCollectionに格納されている行インデックスのコンマ区切りの文字列を作成するだけです。誰かが次のような明らかなメモリを必要とする操作を見つけることができますか?

NB RowCollectionには、整数として格納されている行インデックスのリストが含まれているだけです。

 Private Function GetCommaSeparatedString(ByRef RowIndexes As ArrayList) As String
        Dim RowString As String = String.Empty

        'Build a string of the row indexes 
        'Add one onto each index value so our indexes begin at 1 
        For Each Row In RowIndexes 
            RowString += CInt(Row.ToString) + 1 & ","
        Next

        'Remove the last comma
        If RowString.Length > 0 Then
            RowString = RowString.Substring(0, RowString.Length - 1)
        End If

        Return RowString
    End Function

前もって感謝します。

4

4 に答える 4

4

行の文字列表現が非常に大きい場合を除き、メモリ不足エラーが発生する理由はわかりません。ガベージコレクションできない文字列が1つまたは2つしかないためです。

ただし、作成途中の文字列の内容をコピーするのに非常に多くの時間を費やすため、この方法は非常に非効率的です。StringBuilder は、コンテンツを毎回再作成せずに変更できるため、大きな文字列を作成する場合により適しています。

ただし、この場合、StringBuilder でさえ悪い考えです。なぜなら、文字列を結合していて、それを行うメソッド String.Join が既に存在するからです。LINQ クエリを使用して add-one-to-index-stuff を実行するだけで、ワンライナーが得られます。

Private Function GetCommaSeparatedString(ByVal RowIndexes As ArrayList) As String
    Return String.Join(",", From index In RowIndexes Select CInt(index) + 1)
End Function

また、実際に必要でない限り、参照渡ししないことをお勧めします。RowIndexes を変更していないため、値で渡します。また、インデックスを ToString() してからすぐに解析する理由もわかりません。それらはすでに整数ではありませんか?CIntを使用するだけです。

于 2010-08-31T16:56:26.643 に答える
3

更新: これは stringbuilder を使用するための単純な変更ですが、 StrilancまたはSteven Suditによるより良いアプローチを見てください。

それでもメモリが不足する可能性があります (メモリ有限です) が、文字列を連結するのではなく、StringBuilder を使用する必要があります。毎回、変更するのではなく、新しい文字列オブジェクトを作成しています (文字列は不変であるため)

Private Function GetCommaSeparatedString(ByRef RowIndexes As ArrayList) As String
    Dim RowString As New StringBuilder()

    'Build a string of the row indexes 
    'Add one onto each index value so our indexes begin at 1 
    For Each Row In RowIndexes 
        RowString.AppendFormat("{0},",  CInt(Row.ToString) + 1)
    Next

    'Remove the last comma
    If RowString.Length > 0 Then
        RowString.Append(RowString.Substring(0, RowString.Length - 1))
    End If

    Return RowString
End Function
于 2010-08-31T15:57:38.277 に答える
2

StringBuilder良いアイデアですが、一度にすべてをメモリに保持しようとするのではなく、出力をストリーミングして問題を回避しないのはなぜですか?

于 2010-08-31T16:04:10.713 に答える
1

これは、各反復で、舞台裏で 2 つの文字列を作成しており、それらが最後に近づくにつれて大きくなるためです。

"1,2,3,4,5,....499,500" "1,2,3,4,5,....499,500,"

わずか 500 回の反復の最後に、2000 文字近くの長さの 2 つの文字列を作成し、次の反復でそれらを破棄するだけです (ただし、ランタイムはそれらを保持している可能性があります)。

最後の反復では、行インデックスが連続していると仮定すると、文字列 (1 から 50000 まで) は 100,000 文字になります。これは、〜 10,000,000,000 文字または (2 バイト/文字だと思います) 20 ギガバイトの文字列を割り当てたことを意味します。

文字列 (RowString) のStringBuilder代わりに使用することから始めることができます。+=

Dim RowString As StringBuilder = new StringBuilder( 100000 )

For Each Row In RowIndexes 
    RowString.Append( CInt(Row.ToString) + 1).Append( "," )
Next

'...'

Return RowString.ToString

次のものも試すことができますが、2 つをプロファイルして、最適なものを選択する必要があります。

Private Function GetCommaSeperatedString(ByRef RowIndexes As ArrayList) As String
    Dim indexArray as String[] = RowIndexes
                                 .Select(Function(r)=> (CInt(r.ToString) + 1)ToString)
                                 .ToArray
    return String.Join( ',', indexArray)
End Function



* 注: これらは私が今までに書いた VB の最初の行なので、(特に linq/lambda で) 基本的な間違いを犯した可能性がありますが、要点はそこにあります。

于 2010-08-31T15:56:48.363 に答える