What are some tips I can use to avoid memory leaks in my applications? Are there any gotchas or pitfalls that I can look out for?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
- How to know full paths to DLL's from .csproj f
Use "using" keyword to automatically call Dispose() method of IDisposable object.
For any COM interop you have to manually release all resources.
I know some people are going to advise garbage collection as the solution. But there are lots of cases where garbage collection doesn't give you the results that you expect. It is easy to end up holding on to a stray reference which prevents whole chains of memory from being freed. Read about how this torpedoed a DARPA Grand Challenge entry. You can argue these aren't memory leaks but if the program expects that memory to be freed it is still a problem. Just like in C programming, after a couple of months you get the hang of how to make sure you don't leave unwanted references behind.
I've ran into issues where an object (Ping) implemented Dispose() twice, by implementing the IDisposable interface and inheriting it at the same time. The inherited method did nothing, and as a result you had to cast the object to IDisposable when calling Dispose() or it would leak memory. Here's a post I wrote a few years ago with more detail.
First, let me bring share my strict understanding of a memory leak. My definition of a memory leak is when you have memory you have allocated and no longer a reference to it, so it is not possible to free that memory. Having said that, it is impossible to have a memory leak in .net objects (instances of CTS types that live in the managed heap, I mean). Unreferenced memory is precisely what the GC looks for to free.
Having said that, one can have a more lax understanding of what a memory leak is. If you consider a memory leak to be a uncontrolled growth of the memory being used, well, that is very easy. Just make a big misuse of static variables, mostly ones that reference huge lists. If you keep those objects referenced, the GC will never clean them, promoting them to higher generations and making them even harder to collect. Even though this is not a memory leak in the strict sense, in the end of the day it can lead to similar symptoms. A good way to try to detect this kind of "leak" is to use the CLR Profiler.
Another source of "leaks" is through improper use of event handlers as previously stated. Every time that object A registers one of its instance methods with an event at object B, object B ends keeping an indirect reference to object A, which means that while B is alive, A will be kept alive. Please note however, that there is no circularity here. As soon as neither B or A have any root reference, no matter how many cross references they have, they will eventually be collected.
Finally, one can actually induce a memory leak in .net, but never (at least theoretically) when talking about managed memory, as the GC does an excellent job in clearing that. If any of your objects maintains a reference to unmanaged memory, for instance through interop, then that memory needs to be explicitly cleaned. Failing to do so can lead to a memory leak, indeed. Even though I've never experienced such a scenario, at least in theory this can happen. As previously stated, objects that hold such references ought to implement IDiposable in order to clear that memory and their usage should guarantee Dispose is invoked for that purpose, mainly through the usage of the using clause. Notice that Dispose will not free the object's memory, but will only ask the object to release any unmanaged memory it is referring to.
One special kind of unmanaged memory is the one needed by COM objects used in interop scenarios. These objects are accessed through Runtime Callable Wrappers, RCWs for friends, but have no Dispose. "Using" will not work. The way to release the underlying COM objects is through the static method:
Since "using" is only syntax sugar to call IDisposable.Dispose() in a finally block, it is not usable with RCWs, hence don't forget to place the call in ReleaseComObject(object) in a finally block yourself so you ensure it is really called.
Having a basic understanding of how the garbage collector works will help you avoid abusing memory. For example, if you are keeping a reference to an object you no longer need, the gc won't be able to collect it.
Along the same lines, if you're storing data the the user enters, or data that is added over time, you should consider some kind of limitations so that your memory usage doesn't grow indefinitely.
As others have said call Dispose() (or use a using statement), but additionally consider whether classes use resources and if so implement IDisposeable. This is most often the problem in my code is that I have a class with member that doesn't get cleaned up till a GC.