Утечка памяти, Не уверен, если объект управляется - PullRequest
0 голосов
/ 27 апреля 2011

У меня проблемы с утечкой памяти в C #. Я вижу, что использование памяти в диспетчере процессов увеличивается на 10-20 МБ (и более), когда не нужно создавать новые объекты.

q1) У меня сложилось впечатление, что управляемые объекты будут автоматически удалены GC. Но когда я профилирую использование памяти с помощью dotTrace, кажется, что + 10 000 экземпляров (в показе новых / мертвых различий) базового объекта, который я написал. Я нашел место, где было бы течь, если бы это было C ++,

public void TriggerEvent(string tEvent)
{
    oVariable tVar = GetVar(tEvent);
    if (tVar != null)
        sVariableParser.TriggerEvent(tVar);
    else
    {            
        tVar = new oVariable("@CXZ_TEMP_VAR", tEvent, 0, this);
        tVar._BlockDependancies = true;
        sVariableParser.TriggerEvent(tVar);
    }
}

Где oVariable определяется как

class oVariable : IComparable 

Похоже, что GC не удаляет новые переменные od, мне интересно, нужно ли мне реализовать oVariable как IDisposable и сделать специальный системный вызов, чтобы убедиться, что GC собирает его? В oVariable есть также несколько других пользовательских объектов, но у меня сложилось впечатление, что простыми объектами, которые не используют ничего внешнего (без COM-объектов и т. Д.), Нужно управлять автоматически, или я ошибаюсь, и я создал неуправляемые данные структуры?

q2) Даже если в памяти dotTrace Memory появилось много новых переменных, где их должно быть ноль (возможно, GC ленив), у меня все еще есть ощущение, что утечка памяти может происходить из оконных форм, в частности DataGridViews. Мне было интересно, может ли кто-нибудь сказать мне, нужно ли мне выполнять какие-либо конкретные вызовы функции освобождения памяти после вызова обновления / перерисовки DGV с использованием

tGridView.Invoke(new UpdateGridViewCallBack(RedrawGlobalsViewGridView), tGridView);

Я предполагал, что новый перезвонит уберет за собой.

Ответы [ 3 ]

4 голосов
/ 27 апреля 2011

Во-первых, не вызывайте GC.Collect (), это вызовет сборку мусора, но имеет некоторые неприятные побочные эффекты.Например, он отодвинет все, что не готово для сбора мусора, назад к генерации и задержит его сборку.MS имеет информацию о поколениях и т. Д.

Во-вторых, GC будет собирать объекты только в том случае, если на нее нет ссылок.

Итак, допустим, ваш sVariableParser является переменной-членом, которая содержитссылка на ваш твар.Когда GC запустится, он увидит, что VariableParser зависит от tVar и не отпустит его.

Представьте, что у вас есть что-то вроде этого:

public class House
{
   public Person Resident1 {get; set;}
}

public class Person
{
   public string Name {get; set;}
}

Тогда в вашем коде у вас есть

House.Resident1 = new Person {name = "John Calvin"};

Когда запускается сборка мусора, он не может очистить объект Person, связанный с Resident1, пока Дом не выпадет из области и больше не используется.

Так что все, чтосказать, что GC очистит ваши ссылки, но я предполагаю, что у вас есть некоторый код, удерживающий ваш tVar, и вы этого не понимаете.

2 голосов
/ 27 апреля 2011

Во-первых, GC не находится под чьим-либо непосредственным контролем, а во время выполнения; он будет работать только тогда, когда среда выполнения сочтет это необходимым. Это означает, что объекты, запланированные для очистки, могут сохраняться в течение нескольких секунд или даже минут, пока условия памяти не покажут, что очистка должна быть выполнена.

Однако 10000 мертвых экземпляров, ожидающих очистки, звучат как утечка памяти. Несколько вещей для проверки:

Содержит ли oVariable или ссылается на неуправляемый или IDisposable объект? Если это так, oVariable должен реализовывать IDisposable и выполнять очистку, освобождая ссылки на объекты, которые ему не «принадлежат», и / или удаляя объекты, которые он контролирует. Существует шаблон, который вы можете использовать, чтобы избежать явного вызова Dispose (); посмотрите на http://www.codeproject.com/KB/cs/idisposable.aspx.

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

Наконец, я заметил в вашем комментарии к другому сообщению, что вы поддерживаете иерархические отношения, как вверх, так и вниз, к другим переменным. Пока oVariable находится в любом из этих списков, на него ссылаются. Я бы трижды проверил весь код, который добавляет и удаляет экземпляры из этих списков; вы забываете убирать объекты где-то, так что они торчат бесконечно. Опять же, удаление oVariable должно включать (1) удаление любой ссылки на переменную как Slave из любых / всех Master oVariables, (2) удаление любой ссылки на переменную как Master из любого / всех Slave и, наконец, ( 3) очистка списков Master и Slave переменной. Только когда объект полностью «осиротел» в памяти, GC уничтожит его.

1 голос
/ 27 апреля 2011

Как выглядит внутренняя реализация oVariable? Если вы используете какие-либо активы, которые наследуют IDisposable, вам необходимо закрыть их (или использовать блок using), чтобы убедиться, что они правильно расположены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...