Find references to the object in runtime

21,888

Solution 1

Try using a memory profiler, (e.g. ants) it will tell you what is keeping the object alive. Trying to 2nd guess this type of problem is very hard.

Red-gate gives 14 days trial that should be more then enough time to tack down this problem and decide if a memory profiler provides you with long term value.

There are lots of other memory profilers on the market (e.g. .NET Memory Profiler) most of them have free trials, however I have found that the Red-Gate tools are easy to use, so tend try them first.

Solution 2

You'll have to use Windbg and Sosex extension.

The !DumpHeap and !GCRoot commands can help you to identify the instance, and all remaining references that keep it alive.

Solution 3

I solved a similar issue with the SOS extension (which apparently does no longer work with Visual Studio 2013, but works fine with older versions of Visual Studio).

I used following code to get the address of the object for which I wanted to track references:

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");
        }
    }
}

and then, in Visual Studio 2012 immediate window, while running in the debugger, type:

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

which will load the SOS.dll extension.

You can then use GetAddress(x) to get the hexadecimal address of the object (for instance 8AB0CD40), and then use:

!do 8AB0CD40
!GCRoot -all 8AB0CD40

to dump the object and find all references to the object.

Just keep in mind that if the GC runs, it might change the address of the object.

Solution 4

I've been using .NET Memory Profiler to do some serious memory profiling on one of our projects. It's a great tool to look into the memory management of your app. I don't get paid for this info :) but it just helped me alot.

Solution 5

The garbage collection in .NET is not a counting scheme (such as COM), but a mark-and-sweep implementation. Basically, the GC runs at "random" times when it feels the need to do so, and the collection of the objects is therefore not deterministic.

You can, however, manually trigger a collection (GC.Collect()), but you may have to wait for finalizers to run then (GC.WaitForPendingFinalizers()). Doing this in a production app, however, is discouraged, because it may affect the efficiency of the memory management (GC runs too often, or waits for finalizers to run). If the object still exists, it actually still has some live reference somewhere.

Share:
21,888

Related videos on Youtube

er-v
Author by

er-v

I'm a .net developer, who love find answers on hard questions

Updated on July 09, 2022

Comments

  • er-v
    er-v almost 2 years

    I have an object, which lives forever. I am deleteing all references I can see, to it after using it, but it still not collected. Its life cycle is pretty sophisticated so I can't be sure that all references been cleared.

    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);
    

    How can I find out what references does it still have? Why is it not collected?

    • Lazarus
      Lazarus over 14 years
      Show us your code and we may be able to help. Bear in mind that garbage collection doesn't necessarily happen immediately.
    • Yannick Motton
      Yannick Motton over 14 years
      And I guess the real question is, why are you worrying about it? If you are using Disposable resources, Dispose them when you aren't using them anymore, clean up unmanaged system resources, and watch out with string interning.
    • er-v
      er-v over 14 years
      The code is: 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); But it's still in memory. So it meens, that it steel have roots. How can I find this roots?
    • Sam
      Sam over 14 years
      Are you sure it's in memory? The VM may not give back the memory it used.
    • er-v
      er-v over 14 years
      Sorry for formatting The code is: ` 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); ` But it's still in memory. So it meens, that it steel have roots. How can I find this roots?
    • Joren
      Joren over 14 years
      Why do you even care whether the object is still in memory? The memory is free for all practical purposes: if you need it, the GC will make sure you get it.
    • Joren
      Joren over 14 years
      @er-v: Comments only support very limited formatting. It's best to edit your question instead.
    • Ian Ringrose
      Ian Ringrose over 14 years
      Ok, please tell us what was keeping your object alive...
  • Ian Ringrose
    Ian Ringrose over 14 years
    They also have some free training videos (and documents) etc that explain how the .net garbage collector works that you may find useful.
  • Sam
    Sam over 14 years
    @er-v: your object may have been collected but the memory may not have been reclaimed by Windows. The framework doesn't have to return memory to the OS.
  • Stephen Drew
    Stephen Drew about 10 years
    Agreed, it is a very useful tool, especially the visual stuff.