Колекции и памет

Имам приложение, което чете 3-4 GB данни, изгражда обекти от всеки ред и след това ги съхранява в списъци.

Проблемът, който имах, е, че паметта расте безумно и става около 13 до 15 GB. Защо, по дяволите, съхраняването на тези обекти отнема толкова много памет.

Така че изградих дърво и направих нещо подобно на Huffman Encoding и общият размер на паметта стана около 200 - 300 MB.

Разбирам, че съм компактирал данните. Но не очаквах, че съхраняването на обекти в списъка ще увеличи паметта толкова много. Защо стана така?

какво ще кажете за други структури от данни като речник, стек, опашка, масив и т.н.?

Къде мога да намеря повече информация за вътрешността и разпределението на паметта на структурите от данни?

Или правя нещо нередно?


person DarthVader    schedule 25.03.2011    source източник
comment
Имате ли наистина нужда от всички тези данни (3-4 GB са огромно количество) в паметта? Защо не използвате база данни или не четете само необходимите редове при поискване?   -  person Mayank    schedule 25.03.2011
comment
неуместен. това не беше моят въпрос. но да, имам нужда от всеки ред. и файловете са базата данни. ако правя ред по ред, не мога да паралелизирам програмата.   -  person DarthVader    schedule 25.03.2011
comment
или правя нещо нередно? Да ти си. Късмет!   -  person Mayank    schedule 25.03.2011
comment
Всеки път, когато трябва да заредите 3-4GB данни в паметта и да ги обработите като едно цяло (и не можете да ги разделите на части), тогава в 99% от случаите подхождате към проблема по грешен начин.   -  person Stephen Chung    schedule 25.03.2011
comment
защо не мога да ги нарежа? винаги мога да разделя огромен списък и да обработвам дяловете и да обединявам резултатите. като разделяй и владей.   -  person DarthVader    schedule 25.03.2011
comment
Може би бихте могли да създадете специална структура за обработка на тези видове операции с данни. Обект на базово ниво, настроен за управление на операции като извличане, сортиране, едновременност, използване на паметта и т.н. Този основен обект за управление на данни може да се нарече нещо като база данни. Всъщност тези операции са достатъчно сложни, за да могат някои предприемчиви разработчици да правят пари, продавайки цял продукт, който прави точно това. Бах...това са луди приказки....   -  person Thomas    schedule 25.03.2011
comment
Ако сте задали този въпрос, защото сте любопитни относно структурите на данни, тогава може да искате да прочетете обширен Изследване на структури от данни   -  person Mayank    schedule 25.03.2011
comment
Аз съм с @mayarik, ако имате 3-4 GB данни и те заемат 13-15, тогава правите нещо нередно. Като се има предвид нивото на детайлност във вашия въпрос, това е всичко, което можем да кажем за него, не мислите ли?   -  person Henk Holterman    schedule 25.03.2011
comment
какво мога да направя погрешно, докато чета от файл и съхранявам в списък? :)   -  person DarthVader    schedule 25.03.2011


Отговори (3)


Независимо от структурата на данните, която ще използвате, вашето потребление на памет никога няма да падне под паметта, необходима за съхраняване на всичките ви данни.

Изчислихте ли колко памет е необходима за съхраняване на един обект от клас на екземпляр?

Вашето кодиране на Huffman е спестяваща място оптимизация, което означава, че вие ​​сами елиминирате много дублирани данни в обектите на вашия клас. Това няма нищо общо със структурата на данните, която използвате, за да съхранявате вашите данни. Това зависи от това как са структурирани самите ви данни, така че да можете да се възползвате от различни стратегии за пестене на място (от които кодирането на Huffman е една от многото възможности, подходящо за елиминиране на често срещани префикси и структурата на данните, използвана за съхраняването им, е дърво) .

Сега да се върна на въпроса ви. Без да оптимизирате вашите данни (т.е. обекти), има неща, които можете да внимавате, за да подобрите ефективността на използването на паметта.

Всички наши обекти с еднакъв размер ли са?

Просто изпълнихте ли цикъл, разпределихте памет в движение, след което ги вмъкнахте в списък, като този:

foreach (var obj in collection) { myList.Add(new myObject(obj)); }

В този случай вашият списък обект непрекъснато се разширява. И ако в края няма достатъчно свободна памет за разширяване на списъка, .NET ще разпредели нова, по-голяма част от паметта и ще копира оригиналния масив в новата памет. По същество завършвате с две части от паметта -- оригиналната и новата разширена (сега държи списъка). Направете това много много много пъти (както очевидно трябва за GB данни) и гледате МНОГО фрагментирани пространства в паметта .

Ще бъде по-добре просто да разпределите достатъчно памет за целия списък наведнъж.

Като бележка не мога да не се запитам: как, за бога, света ще търсите в този ОГРОМЕН списък, за да намерите нещо, от което се нуждаете? Не трябва ли да използвате нещо като двоично дърво или хеш-таблица, за да ви помогне в търсенето? Може би просто четете всички данни, извършвате известна обработка на всички тях, след което ги записвате обратно...

person Stephen Chung    schedule 25.03.2011
comment
хаха не търся нищо от списъка. след като попълня данните, генерирам отчет от тях. обобщете резултатите. Искам да прочета всичко наведнъж, за да мога действително да изпълнявам данните паралелно в паметта. разбирам тезата ти. - person DarthVader; 25.03.2011
comment
ако обработвам тези глупости ред по ред, трябва да изчакам IO и това всъщност отнема повече време, отколкото да прочета цялото нещо наведнъж, след което разделяй и владей. - person DarthVader; 25.03.2011
comment
Смисълът на Stephen е, че когато създавате списъка, трябва да прецените или дори по-добре да знаете броя на редовете, така че да изградите списъка с правилния размер още от самото начало. Познаването на размера ще забави първоначалната настройка на списъка, но след това всичко ще стане бързо. - person weismat; 25.03.2011
comment
@user177883, в този случай може да искате, да речем, да импортирате 1000 реда наведнъж. Обработете го. След това импортирайте следващите 1000 реда. Докато не се позовавате на редове навсякъде и просто събирате информация, няма нужда да четете всичко в паметта. - person Stephen Chung; 25.03.2011
comment
@user177883, обработката на файла на блок (да речем 1000 реда) наведнъж също ще работи много по-добре, когато паралелизирате обработката. Ако имате система с 8 ядра, да речем, и поставите на опашка десет милиона задачи към нея, всяко ядро ​​ще има вътрешна опашка от 1 милион задачи -- консумирайки памет, докато чакате. Ако го разделите на блокове, тогава всяко ядро ​​ще има само 100 задачи на опашка към него. Вие не го правите по-бързо от вашия брой ядра -- което е 8 записа наведнъж. - person Stephen Chung; 25.03.2011

В .NET големите обекти отиват в големия обем на обекта, който не е уплътнен. Голямо е всичко над 85 000 байта. Когато увеличите списъците си, те вероятно ще станат по-големи от това и трябва да бъдат преразпределени, след като преминете текущия капацитет. Преместването означава, че те много вероятно ще бъдат поставени в края на купчината. Така че завършвате с много фрагментиран LOH и много използване на паметта.

Актуализация: Ако инициализирате вашите списъци с необходимия капацитет (който можете да определите от DB, предполагам), тогава потреблението на памет трябва да намалее малко.

person ChrisWue    schedule 25.03.2011

Ако използвате класове, прочетете отговора на това: Разбиране на размера на CLR обекта между 32 бита и 64 бита

При 64 бита (използвате 64 бита, нали?) зареждането на обекта е 16 байта ПЛЮС препратката към обекта (някой го препраща, нали?), така че още 8 байта. Така празен обект ще "изяде" поне 24 байта.

Ако използвате Lists, не забравяйте, че Lists растат чрез удвояване, така че може да губите много място. Други .NET колекции растат по същия начин.

Ще добавя, че "чистите" режийни разходи от милиони List могат да поставят паметта на колене. Освен 16 + 8 байта пространство, "изядено" от обекта List, то е съставено (в .NET имплементацията) от 2 int (8 байта), препратка към SyncLock (8 байта, обикновено е нула) и препратка към вътрешния масив (така че 8 + 16 байта + масива)

person xanatos    schedule 25.03.2011