Преобразование типов сжирает RAM

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

Uranium-238
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 28.05.2008 (Ср) 11:25

Преобразование типов сжирает RAM

Сообщение Uranium-238 » 23.10.2015 (Пт) 5:58

Вопроса собственно 2:

Вопрос_1
Код: Выделить всё
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Count As Integer = 50000000
        Dim arrStr(Count) As String

        For x As Integer = 0 To count
            arrStr(x) =Cstr(Count)
        Next

        Dim Proc As Process = Process.GetCurrentProcess
        MsgBox((Proc.PagedMemorySize64 / 1024 / 1024 / 1024) & " Gb")


    End Sub


Этот код сжирает 2,7 Gb оперативы.
Если заполнять массив сразу значением переменной Count arrStr(x) = "50000000" то сожрет 0,4 Gb.
На какие такие нужды ушло 2,3 Gb памяти?

Вопрос_2
После завершения работы процедуры приложение продолжает хавать оперативу до полного завершения работы программы. Как освободить память?

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Преобразование типов сжирает RAM

Сообщение Vi » 23.10.2015 (Пт) 8:57

Uranium-238 писал(а):Вопроса собственно 2:

Вопрос_1
Этот код сжирает 2,7 Gb оперативы.
Если заполнять массив сразу значением переменной Count arrStr(x) = "50000000" то сожрет 0,4 Gb.
На какие такие нужды ушло 2,3 Gb памяти?

На сохранение всех Cstr(Count) из цикла для пищи GC (сборщика мусора).
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 23.10.2015 (Пт) 13:01

Твой код использует (не мусор!) как минимум столько памяти:
Код: Выделить всё
(1*10 + 2*90 + 3*900 + 4*9000 + 5*90000 + 6*900000 + 7*9000000 + 8*40000000) * 2 + 8 + 50000000 * 8 + 50000000 * (8 + 8) = 1977777788
Это приблизительно 1.84 GB. Причём, я, вероятно, недооценил накладные расходы на строки. Ещё +8 байт и будут твои 2.3 GB.

А вот сборщику мусора тут скорее всего почти ничего не достаётся.

Uranium-238
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 28.05.2008 (Ср) 11:25

Re:

Сообщение Uranium-238 » 23.10.2015 (Пт) 15:32

Qwertiy писал(а):
Код: Выделить всё
(1*10 + 2*90 + 3*900 + 4*9000 + 5*90000 + 6*900000 + 7*9000000 + 8*40000000) * 2 + 8 + 50000000 * 8 + 50000000 * (8 + 8) = 1977777788



Очень загадочная строка .... нифига не понял :cyclops:

Но не в строке дело, как тогда заполнить массив рационально?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: Преобразование типов сжирает RAM

Сообщение alibek » 23.10.2015 (Пт) 16:53

Не знаю, как в .NET.
Но обычно рекомендуется выносить одинаковые вычисления из цикла.
Код: Выделить всё
Dim Count As Integer = 50000000
Dim arrStr(Count) As String
Dim v As String
v = Cstr(Count)
For x As Integer = 0 To count
  arrStr(x) = v
Next
Lasciate ogni speranza, voi ch'entrate.

Uranium-238
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 28.05.2008 (Ср) 11:25

Re: Преобразование типов сжирает RAM

Сообщение Uranium-238 » 24.10.2015 (Сб) 12:50

alibek писал(а):Но обычно рекомендуется выносить одинаковые вычисления из цикла.


Одинаковые числа для примера!!! Код решил сократить до минимума.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 27.10.2015 (Вт) 11:08

alibek писал(а):Но обычно рекомендуется выносить одинаковые вычисления из цикла.

Ой.. Я посчитал память для arrStr(x) = CStr(X) :)

Uranium-238 писал(а):Очень загадочная строка .... нифига не понял :cyclops:

Количество строк из 1 цифры - 10 (9 и ещё нолик).
Количество строк из 2 цифр - 90.
...
Количество строк из 7 цифр - 9000000.
Количество строк из 8 цифр - 40000000 (так уж цикл кончился).
На каждый символ в строке тратится по 2 байта.
В сумме (1*10 + 2*90 + 3*900 + 4*9000 + 5*90000 + 6*900000 + 7*9000000 + 8*40000000) * 2 = 777777780 байт.
Сам массив: 8 байт на хранение длины и по 8 байт на ссылку на каждую строку. В сумме 8 + 50000000 * 8 = 400000008 байт.
Внутреннее представление каждой строки: 8 байт на ссылку на массив и 8 неучтённых байт на хранение длины. В сумме 50000000 * (8 + 8) = 800000000 байт.
Итого: 777777780 + 400000008 + 800000000 = 1977777788 байт.
Это самый минимум, который требуется, чтобы всё это хранить.

Uranium-238 писал(а):Но не в строке дело, как тогда заполнить массив рационально?

Эм.. Это и есть рационально. Там даже сборщику мусора ничего не достаётся - выделяется только та память, которую ты реально используешь.
Вероятно, рационально было бы не хранить числа в виде строк?

Uranium-238 писал(а):Одинаковые числа для примера!!! Код решил сократить до минимума.

Тогда пересчитываем формулу выше:
Каждая строка: 8 байт на ссылку на массив символов, 8 байт на длину, 8*2 байт на хранение самой строки, т. е. 32 байта на строку.
Массив по старой схеме 400000008 байт.
Итого: 32*50000000 + 400000008 = 2000000008 байт.

И я не учёл какой-нибудь завершающий 0, всякую информацию о типе объекта и т. д.

Uranium-238
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 28.05.2008 (Ср) 11:25

Re:

Сообщение Uranium-238 » 01.11.2015 (Вс) 4:27

Qwertiy писал(а):Ой.. Я посчитал память для arrStr(x) = CStr(X) :)


Благодарю за столь содержательный ответ!!!


Код: Выделить всё
        For x As Integer = 0 To Count
            arrStr(x) = "0123456789qwertyuiopasdfghjklzxcvbnm"
        Next

Интересно получается... Для хранения этого массива VB выделяет столько-же памяти, как если его вообще не заполнять (просто удалить этот участок кода)
Складывается ощущение что VB статические данные каким-то образом "сжимает" (допустим сохраняя значение и ссылки на ячейки в которых это значение хранится). При этом если значение перед внесением в массив подверглось преобразованию (Cstr-например), то VB честно выделяет под него память.

Такой эксперимент:
Код: Выделить всё
        For x As Integer = 0 To Count
            If x Mod 3 = 0 Then
                arrStr(x) = x
            Else
                arrStr(x) = "0123456789qwertyuiopasdfghjklzxcvbnm"
            End If
        Next

Каждое третье значение в массиве заполнил значением - (x), все остальное - "0123456789qwertyuiopasdfghjklzxcvbnm"
В итоге 1175 Мб

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: Преобразование типов сжирает RAM

Сообщение alibek » 01.11.2015 (Вс) 10:57

Это скорее всего не сжатие.
Не знаю, как в .NET точно, но скорее всего:
Код: Выделить всё
a = "sample"
b = "sample"
# создан один объект, в a и b ссылки на него

a = "sample"
b = a
# создан один объект, в a и b ссылки на него

a = cstr("sample")
b = cstr("sample")
# созданы два объекта, в a ссылка на первый, в b ссылка на второй
Lasciate ogni speranza, voi ch'entrate.

Uranium-238
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 28.05.2008 (Ср) 11:25

Re: Преобразование типов сжирает RAM

Сообщение Uranium-238 » 01.11.2015 (Вс) 17:28

Это проясняет суть дела :)
Остается нераскрытым вопрос №2
Память выделяется в процедуре нажатия кнопки, по завершении ее работы переменные получается продолжают жить или умирают с условием что их место свободно для заполнения программой? Ну типа как файл двоичного доступа (хочешь избавиться от лишнего, сотри и запиши заново).

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 02.11.2015 (Пн) 16:16

Uranium-238 писал(а):Интересно получается... Для хранения этого массива VB выделяет столько-же памяти, как если его вообще не заполнять (просто удалить этот участок кода)

Немного больше. Но хранится только один экземпляр этой строки. Все литеральные строки хранятся в единственном экземпляре.
А строки, созданные динамически - уникальны.

alibek писал(а):# созданы два объекта, в a ссылка на первый, в b ссылка на второй

Не думаю. Не проверял, но 99%, что CStr в данном случае - это просто приведение типа. И приведение типа к самому себе новый объект не создаёт.
При желании можно проверить через Object.ReferenceEquals.

Uranium-238 писал(а):Память выделяется в процедуре нажатия кнопки, по завершении ее работы переменные получается продолжают жить или умирают с условием что их место свободно для заполнения программой?

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

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Преобразование типов сжирает RAM

Сообщение Nord777 » 10.12.2015 (Чт) 12:37

Очистка памяти:
Код: Выделить всё
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()

так как объем массива большой, то можно попробавать так :
Код: Выделить всё
GC.Collect(2, GCCollectionMode.Forced)
GC.WaitForPendingFinalizers()
GC.Collect(2, GCCollectionMode.Forced)

Почитать про управеление памятью тут:
http://rsdn.ru/article/dotnet/GCnet.xml
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 11.12.2015 (Пт) 15:27

Да нечего там чистить.


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

    TopList  
cron