How to break the reference chain?

flipdoubtflipdoubt Posts: 14
In following the advice in the What to look for in the reference graph article about breaking the references that prevent garbage collection, how does one remove a reference? My first answer would be to remove event handlers. My second would be to set the referenced object to null, but I have read many articles that say setting a reference to null does nothing, like this one. Am I missing something?

Speaking of missing something, is it possible for the profiler or even the GC to misplace a reference after you set it to null? I ask this because I tried setting private fields to null in many of my objects Dispose methods, only to find the rate at which Private Bytes shrinks seems to slow down. Even though memory is not freed as quickly, the profiler shows fewer live objects. Has setting the references to null made it more difficult for the profiler to track the objects or has it made it more difficult for the GC to free the memory or something else?

Thanks in advance.

Comments

  • Hi there,

    I would strongly recommend watching the following video (it's in 2 parts):

    Part 1:
    http://www.youtube.com/watch?v=yZ8dC5nlhiY

    Part 2:
    http://www.youtube.com/watch?v=bcM6DoCVtSE

    It was made by a member of the ANTS Team to show a common example of a memory leak in an application and how it was fixed. This should give you a good idea of how to resolve your current issue.

    Stephen
  • I think that stack overflow article could be a bit misleading.

    It doesn't make sense to set local variables to null: the JIT will actually produce code that will do that for you if you're using an optimised build. It won't do so in debug builds: it keeps the value around for longer so it can be inspected in a debugger (this almost never makes a difference in practice).

    With fields, it makes sense to set a reference to null at the point a longer lived object has finished with one that's supposed to be shorter lived. If you don't, both objects will stay in memory for the same length of time. This doesn't really produce a memory leak as such, but can lead to higher overall memory usage.

    If two objects are part of the same structure - that is, they are supposed to be destroyed together then setting their references to null doesn't make sense: the garbage collector will get them both at the same time. For this reason, most of the time it doesn't make sense to set references to null in a Dispose method (but it does make sense to set a reference to null after Dispose has been called on it, as you're not supposed to use it again after that point).

    As to Private Bytes: note that this includes free space that the CLR has reserved for itself and hasn't yet returned to the operating system, so it's possible a fair proportion of that is being unused. This amount of free space is tuned by the CLR to try to maximise performance: it will keep a lot of free memory around if it thinks that your program is about to allocate a lot of objects, for example. It can also have difficulty freeing memory back up again if the large object heap has become fragmented (which depends at least partially on the order of garbage collections and allocations).

    It's not harmful in most cases for .NET to have a lot of free memory around: if it's unused then the operating system is quite good at swapping it out to disk. Heap fragmentation can be a problem, though: it leads to out of memory exceptions, usually while there's theoretically a lot of free space still available. You can see if this is occurring by looking at the summary page: if the number of free bytes is much larger than the largest free block, then your application is almost certainly suffering from fragmentation - if the free bytes are increasing over time then you will eventually suffer an out of memory condition due to this problem. Fixing these issues can be a black art: nulling out references to large objects can make things better or worse depending on what the rest of the program is doing at the time.
    Andrew Hunter
    Software Developer
    Red Gate Software Ltd.
  • Thanks for the pointers to the videos, Stephen. I had already watched the two you reference, but I got more out of the Memory profiling a real world application parts 1 and 2 videos. My question concerns my code which resembles the code shown in the LiveSqlWriter.Dispose() method shown around 1:28 into part 2. Setting references to null, as the Dispose() method does (much like mine), might break part of the reference chain and removing event handlers might break more of it. But is setting references to null and unsubscribing to events all we can do?

    My project has a main form that launches several child forms, much like the video but even uglier. Thanks to the VS.NET designer, this leaves tons of event handlers holding references to the child form that don't get cleaned up. If VS.NET is gracious enough to hook up events in InitializeComponent, why isn't there an UninitializeComponent that does the opposite? Using the object reference graph to determine whether an object is still "live" makes it seem like there absolutely has to be one. But there isn't, so I have to wonder why. If each object does not set each of its private fields to null, why isn't that a leak?
Sign In or Register to comment.