Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Заставить убрать обьекты с памяти.


Автор: Bladerender 24.5.2010, 11:28
Исходные данные.

Код

//Из обьектов этого класса будет состоять колекция
class MyObj
{
   //куча всяких полей, методов, свойств и т.д.
}

//Колекция, с которой нужно будет разобраться. 
List<MyObj> collection = new List<MyObj>();

//Не суть важно. Показать, что коллекция заполняется
collection = FillCollection(param,param1,param1);


Коллекция занимает в памяти ~500 мегабайт.

Код

//Этот код действительно освобождает все 500 мегабайт
collection.Clear();
GC.Collect();


Код

//Этот код ничего не освобождает (почему, я ж так понимаю, что все 500 мегабайт остались без указателя на них и их можно освободить)
collection = null; или collection = new new List<MyObj>();
GC.Collect();



Код

//Этот код тоже естественно ничего не освобождает (исходя из того, что null выше был безполезен)
for(int i=0;i<collecion.Count;i++)
{
collection[i] = null;
}
GC.Collect();


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

К чему собственно эти все разбирательства. Меня интересует именно последний блок кода, т.к. после обработки елемента колекции, мне он уже не нужен, и я хочу, что бы он сразу убирался из памяти.





Автор: Ram1reS 24.5.2010, 14:44
Каким образом Вы определяете что память не освобождена?
GC какбэ недерминировано мусор собирает по необходимости и подгонять его GC.Collect'ами - в большинстве случаев незачем.

ЗЫ. Объекты таких размеров, насколько я понимаю, уходят в LOH, который при сборке не дефрагментируется, так что можете напороться на OOM.

Автор: Rohoss 24.5.2010, 19:19
Цитата(Ram1reS @  24.5.2010,  14:44 Найти цитируемый пост)
Каким образом Вы определяете что память не освобождена?

можно определить по использованной в системе памяти 

Автор: Pilger 24.5.2010, 20:33
А если так.
http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx

Автор: Bladerender 25.5.2010, 00:13
Каким образом Вы определяете что память не освобождена?
Смотрю по ТаскМенеджеру. В первом случае освобождалось. Во всех остальных - нет. 
Pilger Ну я типа почти так и сделал... Написал свой метод класса MyObj, который делает освобождение полям обьекта (колекции чистит, стринги нулит и т.д.). И потом в цыкле, после отработки елемента, вызывал ему свой Dispose(). Получилось.
Объекты таких размеров, насколько я понимаю, уходят в LOH, который при сборке не дефрагментируется, так что можете напороться на OOM.
Я так понимаю, что если объект целиком диспосить, то он тогда туда уходит (что-то типа как я нулил всю колекцию). Вообще этот LOH очень интерестная тема. Давайте создадим отдельную тему и там обсосем это... Очень уж эта память в .Net постоянно куда-то девается...

Автор: PashaPash 25.5.2010, 12:14
Если нужно сначала построить длинный список объектов, а потом для каждого объекта что-то сделать - используй yield/IEnumerable, не создавай огромных массивов.

Pilger, вот так не надо делать. IDisposable не для того предназначен.

Цитата(Bladerender @  25.5.2010,  00:13 Найти цитируемый пост)
Смотрю по ТаскМенеджеру. В первом случае освобождалось. Во всех остальных - нет. 

Не смотри по таскманагеру. Он врет.

Цитата(Bladerender @  25.5.2010,  00:13 Найти цитируемый пост)
Pilger Ну я типа почти так и сделал... Написал свой метод класса MyObj, который делает освобождение полям обьекта (колекции чистит, стринги нулит и т.д.). И потом в цыкле, после отработки елемента, вызывал ему свой Dispose(). Получилось.

Это бесполезное занятие. Достаточно перестать ссылаться на collection, чтобы память под коллекцию, и под все ее объекты могла быть собрана. Перестать ссылаться - не обязательно присвоить null. Даже наоборот - присвоение null продлевает время жизни переменной. 

Механизм работы GC на пальцах: 
GC выделяет под managed-объекты здоровый кусок памяти, который называется managed heap. Память под managed heap выедается относительно большими кусками. Эти куски (а заодно и память, выделенную под код) ты видишь в task manager. А может и не эти - там минимум 3 разных колонки с "памятью" показыватюся, и невозможно угадать на какую именно ты смотришь smile

Внутри managed heap GC выделяет память под объекты. При выделении очередного объекта GC решает что надо бы собрать мусор. Он находит все объекты, на которые есть ссылки в коде, и перекладывает их поплотнее в памяти. Те объекты, на которые ссылок не было при этом затираются.

По каким признакам GC решает запустить сборку мусора - заранее не известно, критерий меняется от версии к версии.

LOH - это отдельный кусок кучи, в котором создаются объекты больше 85000 байт. Отличие LOH от основной кучи - в нем объекты при сборке мусора не перекладываются. Эдакий хак чтобы не перекладывать большие объемы данных. Объект изначально создается или в общей куче, или в LOH, и не "уходит туда-сюда при диспоузе". По той причине что размер объекта в .net - постоянная величина.

Причина по которой не стоит вручную выставлять переменные в null:
Локальная переменная считается корнем в течении своей жизни. Т.е. если она на что-то ссылается - то сборщик мусора считает этот "что-то" достижимым объектом.
Конец жизни переменной:
 - до конца области видимости в Debug
 - до последнего упоминания ее в коде в Release

вписывая collection = null ты "отпускаешь" объект в мусор в Debug. И наоборот, принудительно удерживаешь объект до этой строчки в Release.

Причина по которой не стоит делать такой "Dispose" - как только ты перестанешь ссылаться на объект, он, и все его зависимые куски могут быть собраны GC. Делая ручной Dispose и зануляя ссылки ты получаешь видимое "освобождение", т.к. за время работы "диспоуза" скорее всего происходит сборка мусора. При этом сам объект переживает эту сборку, переползая во первое/второе поколение, которое собирается очень редко. Т.е. ты ухудшаешь ситуацию в долгосрочной перспективе smile

Автор: jonie 25.5.2010, 12:25
в системном мониторе есть счетчики производительности .NET - по ним надо судить, а не по таск менеджеру...

Автор: Bladerender 25.5.2010, 23:37
Т.е. ты ухудшаешь ситуацию в долгосрочной перспективе
На пальцах механизм я понимаю и потому и ждал, что оно все соберется и без моего вмешательства. А на практике получилось, что без моего Dispose этот массив болтался в памяти и в итоге через 3 часа работы программы получал outOfMemory.

Автор: PashaPash 26.5.2010, 00:07
Bladerender, out of memory ты получил из-за фрагментации LOH. Т.е. болтались не сами объекты - они скорее всего были собраны. В LOH выделяется только сам массив ссылок. Т.е. если даже все элементы задиспоужены - LOH уже фрагментирован.

Вообще стоит взять профайлер памяти и посмотреть на приложение. Может там действительно где-то ссылка на массив из статической переменной smile

Автор: uranpro 28.5.2010, 13:37
ну и от event`ов не забудь отписаться)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)