Требуется эффективная функция памяти VB.net - PullRequest
3 голосов
/ 31 августа 2010

Я получаю из памяти исключения из следующей функции, когда RowCollection 50000+ и, следовательно, мне нужно сделать его более эффективным с точки зрения памяти.Функция просто должна создать разделенную запятыми строку индексов строк, хранящихся в RowCollection.Может ли кто-нибудь определить какие-либо очевидные операции, требующие памяти, в следующем?

Примечание. 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 голосов
/ 31 августа 2010

Я не уверен, почему у вас возникают ошибки памяти, если только строковое представление ваших строк не слишком велико, потому что у вас никогда не бывает более одной или двух не подлежащих сборке мусора строк.

Тем не менее, ваш метод является ужасно неэффективным, поскольку он тратит так много времени на копирование содержимого половинных строк.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.

3 голосов
/ 31 августа 2010

Обновление : хотя это прямое изменение для использования stringbuilder, посмотрите на лучшие подходы: Strilanc или Стивен Судит

Что ж, вам все еще может не хватать памяти (в конце концов, память конечна), но вы должны использовать 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 голосов
/ 31 августа 2010

StringBuilder хорошая идея, но почему бы просто не избежать этой проблемы, передавая поток вывода вместо того, чтобы пытаться сохранить все это в памяти сразу?

1 голос
/ 31 августа 2010

Это потому, что на каждой итерации за кулисами вы создаете 2 строки, и они приближаются к концу.

"1,2,3,4,5, .... 499500" "1,2,3,4,5, .... 499500,"

в конце только 500 итераций вы создаете 2 строки длиной почти 2000 символов, чтобы исключить их на следующей итерации (но среда выполнения может их не использовать).

На последней итерации ваша строка (от 1 до 50000) будет иметь длину 100 000 символов, при условии, что ваши индексы строк даже последовательны. Это означает, что вы выделили ~ 10 000 000 000 символов или (я считаю, 2 байта / символ) 20 гигабайт строк.

Вы можете начать с использования StringBuilder вместо += в строке (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

Вы также можете попробовать следующий, но вам следует профилировать два и выбрать лучшее для вас.

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), но суть в этом.

...