Всем привет.
Есть следующая проблемка.
Присутствует достаточно крупное приложение. В последнее время повилась проблема с OutOfMemoryException. Есть подозрение, что один из используемых классов хранит у себя коллекцию чего-то, которую он не подчищает. Классов достаточно много и исходники не всех классов присутствуют.
Баг проявляется только при больших нагрузках на приложение, которые смоделировать не представляется возможным по многим причинам.
Нужно написать какой-нибудь анализатор загруженных в домен библиотек и созданных экземпляров классов на предмет занимаемой ими памяти, чтоб сузить круг поиска бага. Куда смотреть?
Здравствуйте, -Cheese-, Вы писали:
C>Есть следующая проблемка. C>Присутствует достаточно крупное приложение. В последнее время повилась проблема с OutOfMemoryException. Есть подозрение, что один из используемых классов хранит у себя коллекцию чего-то, которую он не подчищает. Классов достаточно много и исходники не всех классов присутствуют. C>Баг проявляется только при больших нагрузках на приложение, которые смоделировать не представляется возможным по многим причинам.
C>Нужно написать какой-нибудь анализатор загруженных в домен библиотек и созданных экземпляров классов на предмет занимаемой ими памяти, чтоб сузить круг поиска бага. Куда смотреть?
Таких анализаторов уже понаписано до вас Вам нужен какой-либо .NET Memory Profiler.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, -Cheese-, Вы писали:
C>Всем привет. C>Есть следующая проблемка. C>Присутствует достаточно крупное приложение. В последнее время повилась проблема с OutOfMemoryException. Есть подозрение, что один из используемых классов хранит у себя коллекцию чего-то, которую он не подчищает. Классов достаточно много и исходники не всех классов присутствуют. C>Баг проявляется только при больших нагрузках на приложение, которые смоделировать не представляется возможным по многим причинам.
C>Нужно написать какой-нибудь анализатор загруженных в домен библиотек и созданных экземпляров классов на предмет занимаемой ими памяти, чтоб сузить круг поиска бага. Куда смотреть?
Здравствуйте, _FRED_, Вы писали: _FR>Таких анализаторов уже понаписано до вас Вам нужен какой-либо .NET Memory Profiler.
это всё понятно, но в режиме отладки смоделировать ситуацию не получается
мне не нужен реал-тайм
я хотел бы в приложение встроить этот анализатор. который каждые минут 5 сохранял статистику и самое главное, чтобы он не мешал приложению работать
C>Присутствует достаточно крупное приложение. В последнее время повилась проблема с OutOfMemoryException. Есть подозрение, что один из используемых классов хранит у себя коллекцию чего-то, которую он не подчищает. Классов достаточно много и исходники не всех классов присутствуют. C>Баг проявляется только при больших нагрузках на приложение, которые смоделировать не представляется возможным по многим причинам.
C>Нужно написать какой-нибудь анализатор загруженных в домен библиотек и созданных экземпляров классов на предмет занимаемой ими памяти, чтоб сузить круг поиска бага. Куда смотреть?
Для начала — просто писать в лог любого типа размер сжираемой памяти. Если вылет происходит не при приближении к лимиту оперативки на приложение и свопа на диске — стоит поискать в выделении больших массивов и утыкать программу GC.Collect(). Сейчас, правда, возможно, поправили, а в Framework 1.1 частое выделение и удаление больших (примерно 100МБ) массивов приводило к OutOfMemory при том, что памяти приложение сожрало даже меньше 1 ГБ. Чисто внутренний баг .NET
Попробуйте вызывать
GC.Collect();
после каждой операции с большими коллекциями/массивами объектов.
Это освободит память, занятую объектами, которые уже не используются.
Иначе CLR будет освобождать память не тогда, когда Вам надо, а когда ему заблагорассудится.
Здравствуйте, vecs, Вы писали:
V>Попробуйте вызывать V>GC.Collect(); V>после каждой операции с большими коллекциями/массивами объектов. V>Это освободит память, занятую объектами, которые уже не используются. V>Иначе CLR будет освобождать память не тогда, когда Вам надо, а когда ему заблагорассудится.
В том числе и тогда, когда память потребуется приложению.
Help will always be given at Hogwarts to those who ask for it.
V>>Иначе CLR будет освобождать память не тогда, когда Вам надо, а когда ему заблагорассудится. _FR>В том числе и тогда, когда память потребуется приложению.
Теоретически, да. И только при условии, что новая память запрашивается непосредственно из managed-кода (нет никаких COM Interop вызовов, процедур в Win32 Dll-ках, не используются сокеты и т.п.).
А еще, вроде бы есть ограничения по объему используемой памяти для .Net приложения. Чуть ли не более 800 — 1000 мегабайт (если Windows не х64). К тому же поговаривают о "прожорливости" некоторых классов типа List<> и Dataset.
Еще видел где-то, что в .Net 2.0 был такой баг (неожиданный OutOfMemoryException) и к нему была выпущена заплатка.
Что касается исходного вопроса по отладке — неужели в отладочном режиме нельзя понять, какие объекты едят память? Даже при минимальной нагрузке должно быть видно.
Здравствуйте, vecs, Вы писали:
V>>>Иначе CLR будет освобождать память не тогда, когда Вам надо, а когда ему заблагорассудится. _FR>>В том числе и тогда, когда память потребуется приложению.
V>Теоретически, да. И только при условии, что новая память запрашивается непосредственно из managed-кода (нет никаких COM Interop вызовов, процедур в Win32 Dll-ках, не используются сокеты и т.п.).
Если память запрашивается из неуправляемого кода, то непосредственного отношения к управляемой куче, за которой следит сборщик мусора, данный запрос отношения иметь не будет.
V>А еще, вроде бы есть ограничения по объему используемой памяти для .Net приложения. Чуть ли не более 800 — 1000 мегабайт (если Windows не х64). К тому же поговаривают о "прожорливости" некоторых классов типа List<> и Dataset. V>Еще видел где-то, что в .Net 2.0 был такой баг (неожиданный OutOfMemoryException) и к нему была выпущена заплатка.
Про Лохнесское Чудовище тоже поговаривают, а оно не виновато.
V>Что касается исходного вопроса по отладке — неужели в отладочном режиме нельзя понять, какие объекты едят память?
А почему должно быть можно "в отладочном режиме" и не должно без него? Управляемые объекты на то и _управляемые_, что среде известно, что за объект занял память.
V>Даже при минимальной нагрузке должно быть видно.
Не вижу, как величина нагрузки может влиять на видимость того, "какие объекты едят память"
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Aviator, Вы писали:
A>Здравствуйте, RadmirT, Вы писали:
RT>>Есть замечательный инструмет JetBrains dotTrace. A>Прям такой уж замечательный... От Red Gate покруче будет.
Что может аттачиться к уже работающим процессам? Или анализировать дампы по 16-20 гигабайт?
Здравствуйте, vecs, Вы писали:
V>>>Иначе CLR будет освобождать память не тогда, когда Вам надо, а когда ему заблагорассудится. _FR>>В том числе и тогда, когда память потребуется приложению.
V>Теоретически, да. И только при условии, что новая память запрашивается непосредственно из managed-кода (нет никаких COM Interop вызовов, процедур в Win32 Dll-ках, не используются сокеты и т.п.).
V>А еще, вроде бы есть ограничения по объему используемой памяти для .Net приложения. Чуть ли не более 800 — 1000 мегабайт (если Windows не х64). К тому же поговаривают о "прожорливости" некоторых классов типа List<> и Dataset.
У List<T> оверхед над T[] ровно в 1 int, насколько я помню.
V>Еще видел где-то, что в .Net 2.0 был такой баг (неожиданный OutOfMemoryException) и к нему была выпущена заплатка.
OutOfMemoryException не означает, что нет свободной памяти. Оно означает, что нет куска нужного размера.
V>Что касается исходного вопроса по отладке — неужели в отладочном режиме нельзя понять, какие объекты едят память? Даже при минимальной нагрузке должно быть видно.
AS>У List<T> оверхед над T[] ровно в 1 int, насколько я помню.
Тут заковыка в том, что память под элементы List<T> выделяется динамически.
Это значит, что при добавлении в список нового элемента (ссылки), под который не хватает выделенной ранее памяти, динамически выделяется память под новые элементы, причем размером в два раза больше, чем текущая емкость списка.
Т.е., например, если в списке 262140 элементов, то при добавлении 262141-го элемента CLR попытается выделить память еще под 262140 элементов, т.е. выделенная в памяти емкость списка сразу станет 524280! А ведь каждый элемент списка — это 4 или 8 байт (в зависимости от разрядности ОС). Вот тут-то нас и может поджидать OutOfMemoryException.
Вот неплохая статья на тему: О побочных эффектах неявного выделения памяти в .Net.
Там, кстати, есть фраза, напрямую относящаяся к описанной в вопросе программе:
"For bulk in-memory data storage, swarms of small objects can push the cost up to unacceptable levels, especially on 64 bit systems."
То бишь: "Одновременное хранение в памяти большой массы мелких объектов может задрать уровень потребления памяти до немыслимого уровня, особенно в 64-разрядной ОС."
Здравствуйте, vecs, Вы писали: V>например, если в списке 262140 элементов, то при добавлении 262141-го элемента CLR попытается выделить память еще под 262140 элементов, т.е. выделенная в памяти емкость списка сразу станет 524280! А ведь каждый элемент списка — это 4 или 8 байт (в зависимости от разрядности ОС). Вот тут-то нас и может поджидать OutOfMemoryException.