Вот о том и речь. После востановаления фокуса твоя мазила сразу отожрала 10 метров памяти, а не 1 метр как ты писал. Сравни это с тем что происходит в дотнетом приложении когда с 60 объем ворксета падает до 5 при наличии фокуса.
ЗЫ
Ктстати, сохранять скриншоты в jpeg так же неразумно как жалеть неиспользуемую памть.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Память и .Net
От:
Аноним
Дата:
28.04.06 10:21
Оценка:
Интересный топик, видно основные проблемы нынешних IT.
Даже боюсь предложить изучать СУ(Р)БД.
P.s. Р в скобках, поскоку других не знаю
Отличный топик получился! Не поленился — прочитал все!
1. Спасибо за то, что хорошо подискутировали на тему памяти — многое для себя устаканил в голове.
2. Собственно по проблеме грида: в упор не понял зачем целиком грузить в память весь список, если в гриде видны несколько (десятков) строк. Это примерно тоже самое, что и пытаться прорисовать ВЕСЬ список, хотя он не влезает на экран.
Вот сколько разных гридов я ни использовал и какие только сумасшедшие объемы через них ни проходили, но всегда проблема памяти не стояла — в памяти были только текущие записи + кэш, который содержал следующую страницу и\или первую\последнюю для быстрой реакции на Home\End.
Вообще не представляю кому пришла в голову идея грузить все — решение же очевидно...
По ходу этой дискуссии видно, что не все представляют, что находится в памяти .NET процессов. Из этого проистекают всякие разные домыслы и предположения, которые по большей части не имеют отношения к действительности. Поэтому я попытаюсь очень кратко показать, как посмотреть в память .NET процесса и определить, зачем она используется и по возможности, как её можно уменьшить.
Для примера я возьму уже обсуждавшееся приложение, в котором создаётся grid и заполняется 10000 строками данных. В моём случае я его ещё дополнил кнопкой "GC.Collect", чтобы вызывать сборку мусора, когда необходимо для тестовых целей. Визуально это выглядит вот так:
Код для приложения элементарен и выглядит так:
for (int i = 0; i < 10000; ++i)
{
string [] rows = new string[3];
rows[0] = i.ToString();
rows[1] = "This is row " + rows[0];
rows[2] = "Data for row " + rows[0] + " is " + rows[0];
dataGridView1.Rows.Add(rows);
}
Теперь приступим к анализу памяти (working set), требуемого этим приложением. Для начала посмотрим, что нам говорит Process Explorer (sysinternals.com): Working Set: 18896KB, Private Bytes: 20300KB. Эти цифры дают примерное представление о размере памяти, необходимой для процесса. Однако, по ним нельзя сказать для чего используется эта память, сколько в ней кода, данных, сколько потребовалось для GC, и т.д. Скудность этой информации даёт некоторым возможность предположить, что большая часть памяти требуется для GC, что GC выделил её с запасом, и он сможет её освободить и вернуть операционной системе, если потребуется. Чтобы понять действительно ли это так нам нужно получить больше информации о памяти нашего процесса.
Используем vadump (msdn.microsoft.com). Команда “vadump -sop <pid>” даёт нам очень красивое summary:
Она представляет из себя сумму по всем модулям процесса. Всего 8MB, т.е почти половина полной памяти не имеет отношения к GC, а является памятью, которую занимают модули. Причём всего 540KB является private для данного процесса. Остальная память либо разделяется между процессами (5316KB) либо может разделяться (2564KB). Посчитать память требуемую модулями .NET я оставлю как задачку для читателей. Модулями .NET являются: mscorwks, mscorjit, mscoree, и все модули оканчивающиеся на .ni.dll (NI – сокращённо native image – модуль, созданный NGEN’ом).
Теперь перейдём к GC. Где его heap? Память, используемая под GC Heap, vadump называет Other Data:
Category Total Private Shareable Shared
Other Data 2072 8288 8284 4 0
Как видим, разделяемой памяти здесь нет, что очень даже логично. Всего мы имеем 8MB, что само по себе не так плохо, хотя и немало. Однако дальше в этом направлении продвинуться с помощью vadump’а сложно. В частности нельзя получить ответы на такие вопросы как: сколько из этой памяти реально используется объектами, а сколько было выделено GC наперёд для своей работы.
Дальше нужно двигаться с помощью windbg и модуля для отладки .NET процессов sos.dll (сокращённо от Son of Strike, в версии 1.0 этот модуль назывался strike).
Итак, запускаем “windbg -p <pid>” и загружаем sos:
0:004> .loadby sos mscorwks
Здесь можно набрать команду !help, чтобы узнать, какие возможности предлагает sos. Нас в данном случае интересует GC Heap, который мы посмотрим следующим образом:
0:004> !EEHeap -gc
Number of GC Heaps: 1
generation 0 starts at 0x01aacfe4
generation 1 starts at 0x018abfbc
generation 2 starts at 0x01381000
ephemeral segment allocation context: none
segment begin allocated size
0016e7c8 7a721784 7a74248c 0x00020d08(134408)
0016a508 7b451688 7b467f9c 0x00016914(92436)
00155a98 790d6358 790f5800 0x0001f4a8(128168)
01380000 01381000 01b1eff4 0x0079dff4(7987188)
Large object heap starts at 0x02381000
segment begin allocated size
02380000 02381000 02386d98 0x00005d98(23960)
Total Size 0x7fa850(8366160)
------------------------------
GC Heap Size 0x7fa850(8366160)
OK. Видно, что vadump нам не соврал. Действительно GC heap в данный момент отнимает ~8.4MB памяти. Однако, не весь GC Heap занят живыми объектами. Какая-то его часть свободна. Это можно узнать, пройдя по всем объектам в хипе:
Теперь понятно, что свободно у нас около 1.3MB. Это та память, которую GC может в принципе отдать OS, но он этого не сделает, потому как по сравнению с полным размером GC Heap (8.4MB) это очень мало. Для compacting GC нормально иметь вдвое больше памяти, чем требуется для живых объектов.
Здравствуйте, alexeiz, Вы писали:
A>OK. Видно, что vadump нам не соврал. Действительно GC heap в данный момент отнимает ~8.4MB памяти. Однако, не весь GC Heap занят живыми объектами. Какая-то его часть свободна. Это можно узнать, пройдя по всем объектам в хипе: A>
A>Теперь понятно, что свободно у нас около 1.3MB. Это та память, которую GC может в принципе отдать OS, но он этого не сделает, потому как по сравнению с полным размером GC Heap (8.4MB) это очень мало. Для compacting GC нормально иметь вдвое больше памяти, чем требуется для живых объектов.
Меня больше привлек такой момент: Free + System.String = 3121016 — что как раз таки показывает прожорливость System.Windows.Forms, а отнюдь не прожорливость GC.
Потому что они при этом получаются хренового качества, не выигрывают в размерах и не пригодны для какй-бы то нибыло дальнейшей обработки.
Скриншоты нужно записывать в GIF (если цветов мало, до 255) или в png.
В jpeg же имеет смысл записывать только фотографии и многоцветные картинки. Вот тут jpeg дает и оптимальное сжатие, и jpeg-артефакты мешают не особо сильно. Правда и тут нужно умудриться не переборщить со степенью сжатия, так как на максимальных степенях jpeg способен угробить любую фотогнафию.
В общем-то это очеведные вещи и любой кто задумается над сутью вопроса может прийти к выводам сам, но почему-то большинство людей упорно не хотят думать и раз за разом наступают на те же грабли.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>В общем-то это очеведные вещи и любой кто задумается над сутью вопроса может прийти к выводам сам, но почему-то большинство людей упорно не хотят думать и раз за разом наступают на те же грабли.
Ужас!
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[24]: Память и .Net
От:
Аноним
Дата:
05.05.06 05:36
Оценка:
Здравствуйте, ie, Вы писали:
ie>Здравствуйте, VladD2, Вы писали:
VD>>В общем-то это очеведные вещи и любой кто задумается над сутью вопроса может прийти к выводам сам, но почему-то большинство людей упорно не хотят думать и раз за разом наступают на те же грабли.
ie>Ужас!
это снова я (prox@inbox.ru)
точно тут подмечено про память на microsoft'e есть статья кто сколько
и какой объект есть память примерно 40% как ни странно string и grid'ы и и списки и все осталоное
и xml И datatable ну прочем чего ожидать от Microsofta они всегда всем свинью подкладывают
и еще раз повторюсь сделайте из топика статью на сайте хотя бы для озанкомления очень хорошо
Здравствуйте, alexeiz, Вы писали:
A>Дальше нужно двигаться с помощью windbg и модуля для отладки .NET процессов sos.dll (сокращённо от Son of Strike, в версии 1.0 этот модуль назывался strike).
А чем не устраивают цифры с закладки .Net в свойствах процесса в упомянутом раньше ProcExp'е?
Здравствуйте, Блудов Павел, Вы писали:
БП>Здравствуйте, alexeiz, Вы писали:
A>>Дальше нужно двигаться с помощью windbg и модуля для отладки .NET процессов sos.dll (сокращённо от Son of Strike, в версии 1.0 этот модуль назывался strike).
БП>А чем не устраивают цифры с закладки .Net в свойствах процесса в упомянутом раньше ProcExp'е?
Я привел всего лишь один пример применения SOS. SOS может использоваться для отладки очень многих вещей в .NET.
Process Explorer берет информацию из performance counter'ов.
Здравствуйте, Блудов Павел, Вы писали:
A>>Дальше нужно двигаться с помощью windbg и модуля для отладки .NET процессов sos.dll (сокращённо от Son of Strike, в версии 1.0 этот модуль назывался strike).
БП>А чем не устраивают цифры с закладки .Net в свойствах процесса в упомянутом раньше ProcExp'е?
Согласен, но alexeiz правильно указал, что SoS позволяет разобраться в том на что тратится память более детально.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Хороший анализ и вообще достойное сообщение. Надо его будет в ФАК засунуть.
Однако кое-что ты все таки не учитывашь. Так что добавлю пару слов.
A>Теперь приступим к анализу памяти (working set), требуемого этим приложением. Для начала посмотрим, что нам говорит Process Explorer (sysinternals.com): Working Set: 18896KB, Private Bytes: 20300KB.
Вот первое на что ты не обратил внимание, а стоило бы.
Практически аналогичный тест на моей рабочей машине привел к тому, что верксет и виртуалка процесса разраслась до ~60 МБ.
На моем ноутбуке этот же тес привел к разростанию ворксета до ~35 МБ в когда в системе было еще много памяти и к 15 когда я загрузил по больше процессов.
По уму конечно надо бы поглядеть рассклад по подробнее, но и так видна общая зависимость. Если в ОС есть много свободной памяти, управляемый процесс использует ее более активно.
Кстати, на основании того, что процесс занял всего 18 МБ можно предположить, что на твоей машине объем памяти составляет что-то около 500 метров. Я угадал?
Таким образом рассуждения о том кто занимает память явно зависят от машины на которой проводятся эксперементы, а стало быть делать выводы нужно куда как осторожнее.
A>
A>Теперь понятно, что свободно у нас около 1.3MB. Это та память, которую GC может в принципе отдать OS, но он этого не сделает, потому как по сравнению с полным размером GC Heap (8.4MB) это очень мало. Для compacting GC нормально иметь вдвое больше памяти, чем требуется для живых объектов.
1. 8 МБ — это размер обычного хипа (не LOH) который по умолчанию выделяется для приложения. Так что если реально объектов меньше, то на занимаемой памяти это скажется не сильно.
2. Не надо забывать, что при востановлении приложения в ворксет попадают только те объекты которые используются выполняемым кодом. Для грида — это в основном DataGridViewTextBoxCell и string. А это в худшем случае 960 192 + 1 829 392 = 2 789 584. Учитывая же, что в дотнете строки юникод, и то что их в 3 раза больше чем у ListView (колонок ведь там никто не создавал). Получаетвя вполне себе нормальная картина. Ну, а если учесть то, что память под 10 000 объектов постоянно не нужна, то вообще не ясно о чем беспокоиться.
3. Хотя в начале сообщения была упомянута кнопка сбора мусора, но в рассуждениях про ее использовние так и небыло сказано. Что немного жаль.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, alexeiz, Вы писали:
A>Я привел всего лишь один пример применения SOS. SOS может использоваться для отладки очень многих вещей в .NET.
+1
A>Process Explorer берет информацию из performance counter'ов.
И тем неменее она куда как удобнее если нужно поглядеть информацию о кучах в целом и статистику сборок мусора. А SoS больше полезен для выявления того куда тратится память.
Добавлю сюда же, что для этих целей так же очень удобно использовать Memory Profiler. Он дает очень интересную статистику.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, ie, Вы писали:
ie>А почему?!
Более точное объяснение: формат JPEG применяет сжатие с потерями. Он основан на предположении о том, что в изображении много плавных переходов и мало резких. Поэтому при сжатии "теряется" как раз информация о резких границах. Визуально это проявляется как грязь вокруг таких границ. Чем больше таких резких переходов — тем ниже коэффициент сжатия и тем хуже конечный результат. Хуже всего — черный текст на белом фоне.
GIF оптимизирован под большие площади, залитые одинаковым цветом, а также под изображения с малым количеством использованных цветов.
Большинство скриншотов используют относительно мало цветов, и относительно много текста/рамочек. Поэтому применение JPEG для них — симптом абсолютного непонимания автором цифровых форматов изображений.
З.Ы. Естественно, сие не догма. Если скриншот должен продемонстировать как раз существенно полутоновые особенности — типа градиентов в заголовках или полупрозрачности окошек — то, конечно, жпег велкам.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Как я понял из дальнейшего обсуждения, ты последовательно игнорируешь все рассуждения опонентов про GC, мотивируя это тем, что чудес не бывает и .net от с++ для win ничем не отличается — перед богом все равны.
Ок.
Допустим, я напишу программу (на чистом c++, разумеется), которая при запуске (и далее по таймеру в 30 секунд) делает одну простую вещь — отжирает ровно 10% от имеющейся свободной памяти. Если выясняется, что программа уже отожрала больше 10% оной — она ее освобождает.
Далее, мы запускаем эту чудо-программу (must have) на машине с гигом свободной памяти — и видим, что она отожрала 100 Мб!!!
Нетрудно подсчитать, что система сможет одновременно выдержать не больше 10 экземпляров оной. Не удивительно, что программы на c++ теряют популярность — при такой-то прожорливости.
Подтвердим теорию практикой — запустим второй экземпляр. Однако он почему-то занял только 90 Мб — странно. Проверив через какое-то время первый экземпляр обнаруживаем, что он теперь занимает 81 Мб — вообще мистика!
А запустив 100 экземпляров получаем (после того, как устаканится своп ) вполне работоспособную систему. Выходит, что с++ не так уж и плох! (В моем примере все 100 экземпляров будут постоянно циклически перестраивать занимаемый собой объем памяти, но это издержки наглядности)
Что мы имеем? Мы имеем систему, которая на первый взгляд кажется черезвычайно прожорливой, а на самом деле — это только фикция. Т.е. модель .net-а.
Я думаю, что теперь настало самое время вернуться к рассмотрению вопроса о том, нафига .net ведет себя таким образом — но это тебе на разные лады повторяли уже раз тридцать по меньшей мере — для эффективности и экономии ресурсов машины.
Здравствуйте, Sinclair, Вы писали:
S>З.Ы. Естественно, сие не догма. Если скриншот должен продемонстировать как раз существенно полутоновые особенности
+1
S> — типа градиентов в заголовках или полупрозрачности окошек — то, конечно, жпег велкам.
-1
Даже в этих случаях jpeg самый плохой выбор. Вот почему:
1. Текста на экране все равно будет много, а значит грязь, грязь и грязь...
2. Градиент в заголовках, даже если речь идет о красивых темах в ХРюше все равно состоит из относительно малого набора цветов.
3. Jpeg дает приемущество от того, что уменьшает количество цветовых переходов в градиентах. Используемые алгоритмы основаны на том предположении, что человек не распознает уж очень плавного изменения цветов, и напротив достраивает его мысленно. А такие переходя есть только на труколорных картинках вроде фотографий.
Для очень навороченных скриншотов обычно лучше всего подходит формат png. Он дает очень высокое качество (особенно если это png 24) и замечательное сжатие для рисованых компьютером изображением.
Так что можно считать железным правилом "jpeg не стоит применять для скриншотов". А выбор между GIF и PNG делать на оновании количества цветов в изображении. Если их больше 20 скорее всего лучше подойдет PNG. А если их еденицы, то GIF.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ie, Вы писали:
ie>>А почему?! S>Более точное объяснение: формат JPEG применяет сжатие с потерями. Он основан на предположении о том, что в изображении много плавных переходов и мало резких. Поэтому при сжатии "теряется" как раз информация о резких границах. Визуально это проявляется как грязь вокруг таких границ. Чем больше
Он не "основан на предположении о том", а просто лучше подходит для таких случаев. А как и все алгоритмы сжатия с потерями основан на том что: любую ф-цию (даже и произвольную кривую и прямоугольные колебания) можно представить набором синусоид (гармоник). И чем больше степень сжатия, тем больше высших гармоник мы убираем, тем грубее приближение полученой суперпозиции оставшихся гармоник. Резкие границы как-раз представляют пример прямоугольного колебания, а в этом случае для более точного приближения результирующей кривой к исходной необходимы как раз высшие гармоники.
Для интересующихся см. раздел высшей математики "Ряды Фурье". Раздел этот появился еще задолго до jpeg-ов и алгоритмов сжатия, в 18 веке вроде.
Здравствуйте, mrozov, Вы писали:
M>Здравствуйте, Pavel Dvorkin,
M>Просто результат наблюдений.
M>Как я понял из дальнейшего обсуждения, ты последовательно игнорируешь все рассуждения опонентов про GC, мотивируя это тем, что чудес не бывает и .net от с++ для win ничем не отличается — перед богом все равны.
Именно так. Все действия GC — внутреннее дело .Net. А для Windows — это процесс, и он подчиняется правилам поведения любых процессов.
Если не согласен — OK, приведи мне какие-нибудь ссылки на то, что ядро Windows хоть что-то знает о .Net и в состоянии отличать процессы .Net от других.
Подчеркиваю — ядро. Все остальное меня просто не интересует, так кая если ядро не знает — то обращаться с процессом .NET оно будет, как и со всеми остальными процессами.
M>Ок.
M>Допустим, я напишу программу (на чистом c++, разумеется), которая при запуске (и далее по таймеру в 30 секунд) делает одну простую вещь — отжирает ровно 10% от имеющейся свободной памяти. Если выясняется, что программа уже отожрала больше 10% оной — она ее освобождает. M>Далее, мы запускаем эту чудо-программу (must have) на машине с гигом свободной памяти — и видим, что она отожрала 100 Мб!!! M>Нетрудно подсчитать, что система сможет одновременно выдержать не больше 10 экземпляров оной. Не удивительно, что программы на c++ теряют популярность — при такой-то прожорливости.
M>Подтвердим теорию практикой — запустим второй экземпляр. Однако он почему-то занял только 90 Мб — странно. Проверив через какое-то время первый экземпляр обнаруживаем, что он теперь занимает 81 Мб — вообще мистика!
Если она у тебя имеет коммитированную память 81 Мб — срочно ищи у себя ошибку, так как она сама декоммитировала 19 Мб . А если речь идет о рабочем множестве, то оно может быть и 10 Мб, и 5 и даже 0 вообще.
M>А запустив 100 экземпляров получаем (после того, как устаканится своп ) вполне работоспособную систему. Выходит, что с++ не так уж и плох! (В моем примере все 100 экземпляров будут постоянно циклически перестраивать занимаемый собой объем памяти, но это издержки наглядности)
M>Что мы имеем? Мы имеем систему, которая на первый взгляд кажется черезвычайно прожорливой, а на самом деле — это только фикция. Т.е. модель .net-а.
Нет. Мы имеем просто-напросто процесс усечения рабочего множество ОС Windows для неактивных процессов (потоки которых находятся в состоянии "не готовы")
M>Я думаю, что теперь настало самое время вернуться к рассмотрению вопроса о том, нафига .net ведет себя таким образом — но это тебе на разные лады повторяли уже раз тридцать по меньшей мере — для эффективности и экономии ресурсов машины.
M>Ага?
Почитай книги по функционированию ОС и системных механизмах.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Почитай книги по функционированию ОС и системных механизмах.
Ты хочешь сказать, что я не смогу написать программу, которая принудительно захватит 100МБ? И освободит половину по мере надобности?
Если я тебя правильно понял, то могу порекомендовать тебе почитать вообще хоть что-нибудь, кроме книг по программированию, а еще лучше — съездить в отпуск, погреть кости на солнышке.
Павел, я тебе описал поведение программы, которое было внесено сознательно. Давай двигаться маленькими шажками.
— Пойдем логическим путем.
— Пойдем вместе.
Веришь ли ты в существование программы, которая выделит себе память... скажем в виде массива цифр от 0 до 10 количеством в 100МБ?
Веришь ли ты в существование программы, которая в какой-то момент (скажем по таймеру) освободит половину этой памяти?
Если нет — ну... может мне и в самом деле стоит освежить свои знания ОС... да и вообще сменить профессию.