2009-09-24 2 views
15

У меня есть объект, который живет вечно. Я удаляю все ссылки, которые я вижу, к нему после использования, но он все еще не собран. Его жизненный цикл довольно сложный, поэтому я не могу быть уверенным, что все ссылки были очищены.Найти ссылки на объект во время выполнения

if (container.Controls.Count > 0) 
{ 
    var controls = new Control[ container.Controls.Count ]; 
    container.Controls.CopyTo(controls, 0); 

    foreach (var control in controls) 
    { 
     container.Controls.Remove(control); 
     control.Dispose(); 
    } 

    controls = null; 
} 

GC.Collect(); 
GC.Collect(1); 
GC.Collect(2); 
GC.Collect(3); 

Как я могу узнать, какие ссылки у него есть? Почему он не собирается?

+0

Покажите нам свой код, и мы сможем вам помочь. Имейте в виду, что сбор мусора не обязательно происходит немедленно. – Lazarus

+0

И я думаю, что реальный вопрос в том, почему вы беспокоитесь об этом? Если вы используете одноразовые ресурсы, удалите их, когда вы их больше не используете, очистите неуправляемые системные ресурсы и следите за ходом строки. –

+0

Код: , если (container.Controls.Count> 0) { \t \t \t \t управления вар = новый контроль [container.Controls.Count]; \t \t \t \t container.Controls.CopyTo (органы управления, 0); \t \t \t \t Еогеасп (управление вар в контрольной группе) { \t \t \t \t \t container.Controls.Remove (контроль); \t \t \t \t \t control.Dispose(); \t \t \t \t \t \t \t \t \t} \t \t \t \t управляет = NULL; \t \t \t} GC.Collect(); GC.Collect (1); GC.Collect (2); GC.Collect (3); Но это все еще в памяти. Так что это мешает, что у него стали корни. Как я могу найти эти корни? –

ответ

11

Попробуйте использовать профилировщик , (например, ants) он расскажет вам, что поддерживает объект. Попытка 2-го угадать, что этот тип проблемы очень тяжелый.

Red-gate дает 14-дневную пробную версию, которая должна быть более чем достаточно, чтобы решить эту проблему и решить, дает ли профилировщик памяти долгосрочную ценность.

Есть много других профайлеры памяти на рынке (например, .NET Memory Profiler), большинство из них имеют бесплатные пробные версии, однако я обнаружил, что Red-Gate инструментов просты в использовании, поэтому, как правило, пытаются их первыми.

+0

Спасибо, я постараюсь! –

+0

У них также есть несколько бесплатных обучающих видеороликов (и документов) и т. Д., Которые объясняют, как работает сборщик мусора .net, который может оказаться полезным. –

+0

@ er-v: ваш объект, возможно, был собран, но память, возможно, не была восстановлена ​​Windows. Фреймворк не должен возвращать память в ОС. – user7116

0

Он не собран, потому что вы не удалили все ссылки на него. GC будет отмечать объекты только для коллекции, если у них нет корней в приложении.

Какие средства вы используете для проверки на GC, чтобы узнать, собрал ли он ваш объект?

2

Коллекция мусора в .NET не является схемой подсчета (например, COM), а реализована пометкой и разверткой. В принципе, GC работает в «случайные» времена, когда он чувствует необходимость сделать это, и поэтому сбор объектов не является детерминированным.

Вы можете, однако, вручную инициировать сборку (GC.Collect()), но вам, возможно, придется ждать завершения финализаторов (GC.WaitForPendingFinalizers()). Однако делать это в производственном приложении не рекомендуется, так как это может повлиять на эффективность управления памятью (GC работает слишком часто или ждет завершения финализаторов). Если объект все еще существует, на нем все еще есть какая-то живая ссылка.

3

Вам необходимо будет использовать Windbg и Sosex.

Команды !DumpHeap и !GCRoot могут помочь вам идентифицировать экземпляр и все остальные ссылки, которые поддерживают его.

3

Я использовал .NET Memory Profiler для выполнения некоторого серьезного профилирования памяти в одном из наших проектов. Это отличный инструмент для изучения управления памятью вашего приложения. Мне не платят за эту информацию :), но это просто помогло мне много.

+0

Согласен, это очень полезный инструмент, особенно визуальный материал. –

3

Я решил аналогичную проблему с расширением SOS (который, видимо, больше не работает с Visual Studio 2013, но отлично работает со старыми версиями Visual Studio).

Я использовал следующий код, чтобы получить адрес объекта, для которого я хотел отслеживать ссылки:

public static string GetAddress(object o) 
{ 
    if (o == null) 
    { 
     return "00000000"; 
    } 
    else 
    { 
     unsafe 
     { 
      System.TypedReference tr = __makeref(o); 
      System.IntPtr ptr = **(System.IntPtr**) (&tr); 
      return ptr.ToString ("X"); 
     } 
    } 
} 

, а затем, в Visual Studio 2012 немедленным окна, во время работы в отладчик, введите:

.load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll 

который будет загружать расширение SOS.dll.

Вы можете использовать GetAddress(x), чтобы получить шестнадцатеричный адрес объекта (например 8AB0CD40), а затем использовать:

!do 8AB0CD40 
!GCRoot -all 8AB0CD40 

сбросить объект и найти все ссылки на объект.

Просто имейте в виду, что если GC работает, это может изменить адрес объекта.

Смежные вопросы