VB.net内存高效功能需要

时间:2010-08-31 15:53:00

标签: .net performance arraylist memory-management string-concatenation

当RowCollection为50000+时,我从以下函数中获取内存异常,因此我需要使其更高效。该函数只需构造一个逗号分隔的行存储在RowCollection中的行索引字符串。以下任何人都可以发现任何明显的记忆饥饿操作吗?

N.B 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 个答案:

答案 0 :(得分:4)

我不确定你为什么会出现内存错误,除非你的行的字符串表示非常大,因为你从来没有超过一个或两个非垃圾收集字符串。

但是,你的方法非常低效,因为它花了很多时间复制半构建字符串的内容。构建大型字符串时,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。

答案 1 :(得分:3)

更新:虽然这是使用stringbuilder的直接更改,但请查看StrilancSteven 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

答案 2 :(得分:2)

StringBuilder是一个好主意,但为什么不通过将输出流式传输而不是尝试将其全部保存在内存中来避免问题呢?

答案 3 :(得分:1)

这是因为在每次迭代中,你在幕后创建2个字符串,并且它们越来越接近结尾。

“1,2,3,4,5,... 499500” “1,2,3,4,5,... 499,500,”

在仅500次迭代结束时,您创建了2个字符串,长度接近2000个字符,只是为了让它们在下一次迭代中被丢弃(但运行时可能会保留它们)。

在最后一次迭代中,假设您的行索引是连续的,那么您的字符串(从1到50000)将是100,000个字符长。这意味着你已经分配了~100,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

您也可以尝试下一个,但您应该对这两个进行分析并为您挑选最佳选择。

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的东西中),但问题就在那里。