VB.net 需要内存高效功能

发布于 2024-09-16 21:25:48 字数 755 浏览 4 评论 0原文

当 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

提前致谢。

I'm getting out of memory exceptions from the following function when RowCollection is 50000+ and thus i need to make it more memory efficient. The function is simply needs to construct a comma separated string of the row indexes stored in RowCollection. Can anyone spot any obvious memory hungry operations in the following?

N.B RowCollection just contains a list of row indexes stored as integers.

 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

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酸甜透明夹心 2024-09-23 21:25:48

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

但是,您的方法效率非常低,因为它花费了大量时间来复制半构建字符串的内容。 StringBuilder 更适合构建大型字符串,因为可以修改它而无需每次都重新创建内容。

然而,在这种情况下,即使使用 StringBuilder 也是一个坏主意,因为您正在连接字符串,并且已经有一个方法可以做到这一点:String.Join。只需使用 LINQ 查询来执行“向索引添加一”的操作,您就会得到一行:

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 即可。

I'm not sure why you're getting out of memory errors, unless the string representation of your rows is extremely large, because you never have more than one or two non-garbage-collectible strings.

However, your method is horribly inefficient because it spends so much time copying the contents of half-built strings. A StringBuilder is more appropriate when building large strings, because it can be modified without re-creating the contents each time.

HOWEVER, in this case even a StringBuilder is a bad idea, because you are joining strings and there is already a method to do that: String.Join. Just use a LINQ query to do the add-one-to-index-stuff and you get a one-liner:

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

I would also recommend not passing by reference unless you actually need it. You aren't modifying RowIndexes, so pass it by value. I'm also not sure why you are ToString()-ing the index then immediately parsing it. Aren't they already integers? Just use CInt.

2024-09-23 21:25:48

更新:虽然这是使用 stringbuilder 的直接更改,但请通过 Strilanc史蒂文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

Update: while this is a straight change to use stringbuilder, look at the better approaches by Strilanc or Steven Sudit

Well, you may still run out of memory (memory is finite, after all), but you should be using a StringBuilder, not concatenating strings. Each time, you are creating a new string object rather than changing it (As strings are immutable)

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
慈悲佛祖 2024-09-23 21:25:48

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

StringBuilder is a good idea, but why not just avoid the problem by streaming the output out instead of trying to hold it all in memory at once?

油饼 2024-09-23 21:25:48

这是因为在每次迭代中,您都会在幕后创建 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 的字符串。

您可以首先在字符串 (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 方面),但重点就在那里。

This is because in each iteration, behind the scenes you are creating 2 strings, and they are getting big nearer the end.

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

at the end of only 500 iterations, you are creating 2 strings nearly 2000 characters long, only to have them discarded in the next iteration (but the runtime may be keeping them around).

In the last iteration, your string (from 1 to 50000) would be 100,000 characters long, assuming your row indexes are even sequential. This would mean you have allocated ~ 10,000,000,000 characters or (I believe 2 bytes/char) 20 gigabytes of strings.

You can start by using StringBuilder instead of += on a string (RowString).
Ex

Dim RowString As StringBuilder = new StringBuilder( 100000 )

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

'...'

Return RowString.ToString

You can try the next one as well, but you should profile the two and pick the best for you.

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

* note: these are the first lines of VB I've ever written, so I may have made a basic mistake (especially in the linq/lambda stuff), but the point is there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文