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

我不确定你为什么会出现内存不足错误,除非你的行的字符串表示非常大,因为你永远不会有超过一两个不可回收的字符串。

但是,您的方法效率极低,因为它花费大量时间复制半构建字符串的内容。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()-ing 索引然后立即解析它。他们不是已经整数了吗?只需使用 CInt。

于 2010-08-31T16:56:26.643 回答
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
于 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 次迭代结束时,您将创建 2 个近 2000 个字符长的字符串,只是为了让它们在下一次迭代中被丢弃(但运行时可能会保留它们)。

在最后一次迭代中,您的字符串(从 1 到 50000)将是 100,000 个字符长,假设您的行索引甚至是连续的。这意味着您已经分配了大约 10,000,000,000 个字符或(我相信 2 个字节/字符)20 GB 的字符串。

您可以从使用StringBuilder而不是+=字符串 (RowString) 开始。
前任

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

于 2010-08-31T15:56:48.363 回答