Здравствуйте, Jolly Roger, Вы писали:
JR>Да, С2 требует. Но если я правильно помню, прямой корелляции между освобождённой памятью и изменением рабочего набора я не заметил. То есть механизм, видимо, действует несколько сложнее. Впрочем, так как это было не вчера, то есть вероятность, что память меня таки подводит В любом случае, каждый желающий всегда может поставить экспиремент самостоятельно.
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, koandrew, Вы писали:
K>>Это не так. Винда (по крайней мере серверная) сертифицирована по стандарту безопасности С2, который среди всего прочего требует, чтобы ядро ОС всегда обнуляло страницы перед передачей их приложению. Об этом кстати у Рихтера написано.
JR>Да, С2 требует. Но если я правильно помню, прямой корелляции между освобождённой памятью и изменением рабочего набора я не заметил. То есть механизм, видимо, действует несколько сложнее. Впрочем, так как это было не вчера, то есть вероятность, что память меня таки подводит В любом случае, каждый желающий всегда может поставить экспиремент самостоятельно.
C2 требует именно обнуления памяти перед выдачей ее процессу?
Может быть требуется просто не допускать возможности чтения процессом чужого "мусора" в свежеполученной памяти? Это ведь разные вещи. Возможность чтения процессом собственного "мусора" врядли повлияет на безопасность.
Почему-то я примерно так это себе и представляла.
Работающий код, пожалуйста. То, что вы написали, работать не может.
Ну даже если предположим, что myReader, MapIDReader и MapID — это одна и та же переменная, которая переименовалась при копипасте, то все равно надо ридеры закрывать внутри цикла, т.е. на каждый new StreamReader должен быть вызов StreamReader.Close().
А в вашем коде вы закрываете только один последний, а создаете их много — по одному для каждого файла.
Здравствуйте, v.a.v, Вы писали:
VAV>C2 требует именно обнуления памяти перед выдачей ее процессу? VAV>Может быть требуется просто не допускать возможности чтения процессом чужого "мусора" в свежеполученной памяти? Это ведь разные вещи. Возможность чтения процессом собственного "мусора" врядли повлияет на безопасность.
С2 требует обнуления, если страница передаётся другому процессу и если она была текущим процессом модифицирована. В этом случае она попадает к потоку обнуления страниц, а оттуда опять в ведение менеджера набора.
Да это я читал, а что не так? Это описание слишком уж расплывчатое, явно видно цель — не сказать-бы чего лишнего Но и там, кстати сказано "Pages can be removed", а не, скажем "are removed", да и VirtualFree не упомянута, хорошо хоть про VirtualUnlock не забыли
Закрывать конечно надо, всё правильно, только вряд-ли это повлияет на обсуждаемое. Не тот показатель ТС использует. Да и вообще, пытаться определить утечки с помощью дисперчера задач для приложений, имеющих локальный менеджер памяти — занятие, мягко говоря, странное. Это его работа, локального менеджер — брать у системы большие регионы памяти и потом выдавать приложению частями по мере надобности, для того локальные менеджеры и пишутся даже там, где GC нет. Ну и отдавать системе память сразу при её освобождении приложением было-бы неразумно с точки зрения производительности, ни один менеджер этого и не делает, а диспетчер задач видит именно то, что взял у системы локальный менеджер процесса. Тем более что это просто диапазон адресов, имеющий смысл только для локального процесса, и влияние его на другие процессы и систему в целом весьма ограничено. Впрочем, об этом уже говорилось.
Здравствуйте, notacat, Вы писали:
N>Почему-то я примерно так это себе и представляла. N>Работающий код, пожалуйста. То, что вы написали, работать не может.
N>Ну даже если предположим, что myReader, MapIDReader и MapID — это одна и та же переменная, которая переименовалась при копипасте, то все равно надо ридеры закрывать внутри цикла, т.е. на каждый new StreamReader должен быть вызов StreamReader.Close(). N>А в вашем коде вы закрываете только один последний, а создаете их много — по одному для каждого файла.
Извиняйте, копипаст действительно кривой, не проверил.
Вот полный код метода:
private string[] GetSocMapNames(string RootFolder)
{
string[] Maps = Directory.GetFiles(RootFolder + @"\mods", "*.xdb0");
string[] MapNames = new string[Maps.Length];
string MapLine = "", MapName = "";
StreamReader MapID = null;
int i = 0;
foreach (string map in Maps)
{
Application.DoEvents();
MapID = new StreamReader(map, Encoding.GetEncoding(1251));
while (!MapID.EndOfStream)
{
MapLine = MapID.ReadLine();
if (MapLine.Contains(@"map\"))
{
MapLine = MapLine.Trim();
if (MapLine.StartsWith("texture"))
{
MapName = MapLine.Substring(MapLine.IndexOf(@"map\") + 8); ////break;
}
}
}
MapNames[i] = MapName;
i++;
}
MapID.Close();
return MapNames;
}
...
О чём и говорили. Закрывай стримы явно каждый либо (что лучше) просто используй using.
Сообщение заговорено потомственным колдуном, целителем и магом в девятом поколении!
Модерирование или минусование сообщения ведет к половому бессилию, венерическим заболеваниям, венцу безбрачия и диарее!
Здравствуйте, Flammable, Вы писали:
F>Вот полный код метода:
1) Повесить using на создание reader, убрать Close().
2) Этот код будет падать (NullReferenceException) если в каталоге нет ни одного файла с нужной маской (на MapID.Close()).
3) MapName не чистится в каждой итерации цикла — в итоге MapNames[] может оказаться заполнен мусорными значениями с прошлых итераций (в первом файле texture была, в остальных нет)
4) DoEvents действительно здесь нужна? Просто практика показывает что от этого метода проблема ой как много, а нужен он ой как редко.
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, v.a.v, Вы писали:
VAV>>C2 требует именно обнуления памяти перед выдачей ее процессу? VAV>>Может быть требуется просто не допускать возможности чтения процессом чужого "мусора" в свежеполученной памяти? Это ведь разные вещи. Возможность чтения процессом собственного "мусора" врядли повлияет на безопасность.
JR>С2 требует обнуления, если страница передаётся другому процессу и если она была текущим процессом модифицирована. В этом случае она попадает к потоку обнуления страниц, а оттуда опять в ведение менеджера набора.
И я о том-же. Нет смысла обнулять страницу если планируется её вернуть тому-же процессу. Это не противоречит требованиям C2.
А учитывая что:
"Pages can be removed", а не, скажем "are removed"
Вы были правы, что станицы могут не удаляться из рабочего набора, сразу после их освобождения процессом.
JR>Закрывать конечно надо, всё правильно, только вряд-ли это повлияет на обсуждаемое. Не тот показатель ТС использует. Да и вообще, пытаться определить утечки с помощью дисперчера задач для приложений, имеющих локальный менеджер памяти — занятие, мягко говоря, странное.
Поверьте на слово, что если упорно не закрывать стримы и не освобождать ссылки, то даже диспетчер задач это покажет. И если сделать пример, в котором подозрительные действия выполняются в цикле, и аккуратно просить каждый раз GC все лишнее почистить, то за несколько итераций в диспетчере задач прекрасно видно, течет память или не течет.
А вот остальные детали и лечение — это уже конечно не к диспетчеру задач надо обращаться.
Ну и отдельный вопрос — что половина участников уже забыла, что нужно было топик стартеру. Вы уже все внутренности Windows обсудили, но это не значит, что именно это является обсуждаемым.
Здравствуйте, Don Reba, Вы писали:
DR>Здравствуйте, Jolly Roger, Вы писали:
JR>>Если не хочется углубляться в механизмы, то можно принять за аксиому, что управление памятью в Windows писали отнюдь не ламеры. NET'овскую надстройку, я думаю, тоже.
DR>Только, далеко не факт, что ценности этих не-ламеров совпадают с вашими.
Этот господин Jolly Roger уж очень себя любит и в оскорбительном тоне участвует в обсуждениях. Он обычно изначально уверен в совершенстве мелкософтовских технологий, практически задом своим отвечает
Здравствуйте, Jesmus, Вы писали:
J>Здравствуйте, Flammable, Вы писали:
F>>Вот полный код метода:
J>1) Повесить using на создание reader, убрать Close(). J>2) Этот код будет падать (NullReferenceException) если в каталоге нет ни одного файла с нужной маской (на MapID.Close()). J>3) MapName не чистится в каждой итерации цикла — в итоге MapNames[] может оказаться заполнен мусорными значениями с прошлых итераций (в первом файле texture была, в остальных нет) J>4) DoEvents действительно здесь нужна? Просто практика показывает что от этого метода проблема ой как много, а нужен он ой как редко.
2. В каталоге всегда есть файлы Хотя, чем черт не шутит. Надо и это предусмотреть, спасибо.
3. Разве присваивание переменной нового значения не удаляет старое?
4. DoEvents действительно нужна, иначе форма зависает. Файлы объемные, читаются не моментально. А что за проблемы с этим методом?
Здравствуйте, v.a.v, Вы писали:
VAV>Вы были правы, что станицы могут не удаляться из рабочего набора, сразу после их освобождения процессом.
Может да, а может нет В принципе, обнуление страницы может быть выполнено и без удаления из рабочего набора процесса, в системе есть функция для быстрого обнуления страниц, что-то вроде MmZeroInPage или похоже. Но и для противоположного мнения можно найти аргументы. В любом случае, точный ответ знают только разработчики. Но ведь с точки зрения прикладного кода это и не суть важно. Важно то, что мы имеем дело с виртуальной памятью, а отображением её на физическую полностью заведует система. Есть, правда, исключение в виде VirtualLock, но это именнно что исключение.
Здравствуйте, Flammable, Вы писали:
J>>2) Этот код будет падать (NullReferenceException) если в каталоге нет ни одного файла с нужной маской (на MapID.Close()). J>>3) MapName не чистится в каждой итерации цикла — в итоге MapNames[] может оказаться заполнен мусорными значениями с прошлых итераций (в первом файле texture была, в остальных нет) J>>4) DoEvents действительно здесь нужна? Просто практика показывает что от этого метода проблема ой как много, а нужен он ой как редко.
F>2. В каталоге всегда есть файлы Хотя, чем черт не шутит. Надо и это предусмотреть, спасибо. F>3. Разве присваивание переменной нового значения не удаляет старое? F>4. DoEvents действительно нужна, иначе форма зависает. Файлы объемные, читаются не моментально. А что за проблемы с этим методом?
2) Ох, если бы мне за каждое "всегда будет" давали денежку когда в эксплуатации оказывалось что и не всегда, и не будет
3) У тебя проблема что новое значение присваивается не всегда, а только если отработает условный блок. Если ни одной "map" или "texture" в файле нет, то нет присвоения => в переменной значение со старого прохода цикла => в массиве мусор. На "всегда будут эти значения" я уже сверху ответил. Пользователи вообще такие шалуны порой
4) Проблемы синронизации. Код с DoEvents должен быть спроетирован также как код с использование потоков — а почему бы тогда не использовать потоки сразу? И опыт подтверждает — видишь в коде DoEvents — будь готов к проблемам, когда пользователь не там щелкнул, сработало событие таймера и изменило состояние объектов посреди метода и прочие прелести многопоточного программирования. Вот быстро нагуглил несколько статей по поводу DoEvents:
Здравствуйте, Jesmus, Вы писали:
J>4) Проблемы синронизации. Код с DoEvents должен быть спроетирован также как код с использование потоков — а почему бы тогда не использовать потоки сразу? И опыт подтверждает — видишь в коде DoEvents — будь готов к проблемам, когда пользователь не там щелкнул, сработало событие таймера и изменило состояние объектов посреди метода и прочие прелести многопоточного программирования.
Здравствуйте, notacat, Вы писали:
N>Поверьте на слово, что если упорно не закрывать стримы и не освобождать ссылки, то даже диспетчер задач это покажет. И если сделать пример, в котором подозрительные действия выполняются в цикле, и аккуратно просить каждый раз GC все лишнее почистить, то за несколько итераций в диспетчере задач прекрасно видно, течет память или не течет. N>А вот остальные детали и лечение — это уже конечно не к диспетчеру задач надо обращаться.
Я безусловно и с удовольствием верю Вам на слово, но для приобретения опыта хотелось-бы увидеть явление своими глазами Я вот взял код, приведённый ТС, и запустил его без единого изменения на директории с 1000-й файлов, и даже без принудительного вызова GC.Collect. При первом запуске метода объём Working set вырос с 12288 до 14552, а витуальной памяти — с 11600 до 13572. Дальнейшие многократные запуски этого кода не привели к какому-либо росту обоих показателей, они то чуть возрастают, то чуть уменьшаются. Дескрипторы тоже не растут, что по-моему неудивительно, они ведь завёрнуты в SafeHandle, имеющий деструктор, и GC их в своё время закрывает. Я так понимаю, закрывать стрим нужно, чтобы освободить файл немедленно, а иначе он всё равно будет закрыт коллектором, только несколько позже. Я конечно за то, чтобы закрывать такие ресурсы сразу, но и без этого утечки хёндлов в DotNet не будет. Признаться, наблюдаемое поведение совпадает с моими представлениями, но может быть мои представления ошибочны? Как мне увидеть то явление, о котором вы говорили — то есть наблюдаемую в диспетчере ктечку от незакрытых явно стримов?
N>Ну и отдельный вопрос — что половина участников уже забыла, что нужно было топик стартеру. Вы уже все внутренности Windows обсудили, но это не значит, что именно это является обсуждаемым.
Но ведь эта половина не виновата, что данное явление тесно связана с системными сервисами, без знакомства с которыми невозможно правильно расставить акценты Я вот пытался объяснить ему, почему он эти данные не подходят, но видимо безуспешно А судя по раздражённому тону Вашего поста, он не одинок, но разве это моя вина? Может быть, чтобы никого не раздражать, мне следовало поддержать его мнение, хотя я знаю, что это полная чушь? Как Вы считаете?