In part 1 of this series of this article, I talked about the fact that it is very critical for every developer to know exactly how memory management works in the .NET runtime. In part 2 I showed how to implement the IDisposable interface for your types. In this article, I am going to discuss how to find these issues in your code by using tools and Visual Studio extensions.
I will be using the code base that I mentioned in part 1 that has over 1 million lines of code. This solution uses the .NET Framework the most and has a few .NET Core projects. As I stated in part 1, I found over 600 places in the code where Dispose() is not being called on Disposable types. I found 90 types that either did not implement IDisposable or at all. All this work created over 2,000 touchpoints in the code that needs to be changed, code reviewed, tested, and deployed.
Tool |
Dispose/ IDisposable Issues |
Total Violations |
CodeIt.Right |
None |
9,843 |
CodeRush |
None |
6,760 |
NDepend |
72 |
36,268 |
ReSharper |
3 |
101,901 |
SonarLint |
25 |
8,540 |
Visual Studio Analyze |
None |
48,409 |
Not only do these tools have a different number of code violations found but only 3 of them found ANY Dispose/ IDisposable issues! The number they should have found is around 1K violations. Sadly, finding all these issues still boils down to a lot of manual searching. Let’s discuss these tools along with newer analyzers (SonarLint) that might also help.
CodeIt.Right
CodeIt.Right is a static code analyzer from Submain.com. I have spoken about CodeIt.Right many times at conferences and my latest article titled “Analyzing Code for Issues: CodeIt.Right” can be found here. I do use it to analyze .NET Framework projects because not only does it find issues, in most cases they can be fixed by just clicking a button! Unfortunately, it did not find any dispose issues in this codebase.
CodeRush
Ever since it was released, I have been using CodeRush from DevExpress.com to help refactor code in VB.NET and C#. It even has the functionality to make it easier to correct code smells, complete code, navigate, search for symbols, highlight the structural elements of the code, format code, and generate and optimize code. I always use Test Runner that is included in CodeRush, since it runs unit tests faster! I have previously written about CodeRush in this article. Sadly, it did not find any dispose issues in this codebase.
NDepend
For this article, I am using the NDepend static code analyzer (NDepend has many more features). It will likely find hundreds or even thousands of issues affecting your codebase. It found a total of 72 issues and 70 of them were about classes that did not properly implement IDisposable. One feature that I like with NDepend is when you analyze your code, it estimates the time it will take to fix them. In this codebase, that number is 858 man-days! So far, this is the only tool that found these types of issues! Sadly, it did not find any of the places in the code that Dispose is not being called and more.
Resharper
Just like CodeRush, Resharper from JetBrains is a refactoring tool for Visual Studio. Resharper did find three dispose issues in the code. All three are “Instance of IEnumerator is never disposed”. I’ve never seen this type of violation before. Sadly, there are hundreds of issues in this code base that Resharper missed.
SonarLint
SonarLint from SonarSource is a Free IDE extension that identifies and helps you fix quality and security issues as you code. Like a spell checker, SonarLint squiggles flaws and provides real-time feedback and clear remediation guidance to deliver clean code from the get-go. SonarLint found 25 dispose issues in this codebase. They are:
- Either implement 'IDisposable.Dispose', or totally rename this method to prevent confusion.
- Fix this implementation of 'IDisposable' to conform to the dispose pattern.
- Refactor this code to make sure 'ms' is disposed only once.
- Dispose 'myWebClient' when it is no longer needed.
I’ve never used SonarLint before to analyze code. After getting to know it for this article, I do plan to add it to the tools that I use to analyze code. It even has a sense of humor as seen in this violation description:
“Drop this useless call to 'ToList' or replace it by 'AsEnumerable' if you are using LINQ to Entities.”
Like all the tools in this article, it missed hundreds of dispose issues in this codebase.
Visual Studio Analyze
I have spoken at conferences many times about Visual Studio Analyze and have written about it. My latest article titled “Analyzing Code for Issues: Visual Studio Analyze” can be found here. I use Visual Studio Analyze before I commit any code to source control. But for this codebase, Analyze did not find a single dispose issue.
.NET Memory Profiler
I have stated many, many times, “Performance affects memory and memory affects performance”. None of the code analysis tools I’ve written about will find every issue when it comes to memory and performance. The only way to find the rest is by using a memory profiler tool on running code as near to production machine setup as possible.
Make sure you allocate time to analyze the report from these tools. In most cases, it takes a lot of time to go through the report to find the issues you are looking for. Also, not every developer on your team needs a license to memory profilers, only the developers who fully understand memory management and understand how to analyze these reports.
I’ve tried all the major tools on the market and the one that I like the best is .NET Memory Profiler from SciTech Software. This tool will profile any .NET process including ASP.NET, Windows Store App, remote processes and it supports .NET Core. I have previously written about this tool here.
The way that the codebase that I have been using for this article was architected, it’s horribly difficult to use this tool on it. So, I decided to run it against Visual Studio since it is partially written in .NET.
Here are a few examples of the result of running a memory profiler session. This shows that there are undisposed instances of the Control and ImageList type.
This shows that there are potential WPF binding memory leaks in 86 instances in memory.
This shows that there are objects that have been disposed of but not garbage collected.
The issues are being detected in the AsyncSemaphore type. Using the graph view, you can move up and down the call stack. I would guess that the issue is somewhere in the two boxes above AsyncSemaphore.
I don’t have the source for Visual Studio, so I can’t show you where in the code that these issues are happening. As you can see, using a memory profiler can find issues that no analyzer can, so it’s always important to run a session on your code before release so you can find all the remaining issues. I have yet to work at a company where this was common practice.
Summary
This article shows that to find memory issues and disposable issues in .NET code, you should use tools and your brain to find them since NONE of the tools I use or tested found all the issues that I found. To help you find issues manually in your code, I will keep up to date the common types to look for that I wrote about in part one of this series.
I hope this article inspires you and your team to find and destroy any memory or disposable issues in your code. In most cases, it will also increase the performance of your application too!
How do you find these types of issues in your codebase? I’d love to know so I hope you will comment below. To help you, don’t forget to pick up a copy of my coding standards or code performance book by going here.
You can get a copy of CodeRush for FREE (fully licensed) by just watching an episode of Rockin’ the Code World with dotNetDave.
Since none of these tools found all the issues that I did manually, I am thinking of creating a new conference talk about these articles. What do you think?