Think with Enlab

Diving deep into the ocean of technology

Stay Connected. No spam!

How to Inspect and Improve Memory Usage With dotMemory

 

In .NET programming, coding with care when using static variables, disposable objects, events, and threads as memory leak can happen if we don’t code the right way. In this article, I’d like to share with you a powerful tool to detect and resolve memory leak issues - that is dotMemory.

 

How to Find Memory Leak Using dotMemory

First of all, what is a memory leak? According to pcmag.com, it is “a condition caused by a program that does not free up the extra memory it allocates.” And jetbrains.com says “a memory leak is a result of incorrect memory management when an object is stored in memory but cannot be accessed by the running code." Also, “memory leaks add up over time, and if they are not cleaned up, the system eventually runs out of memory.”

General steps to detect and analyze memory leak issues using dotMemory:

Step 1. Run dotMemory application and config to run your application

Step 1. Run dotMemory application and config to run your application
In my example, I am configuring to run a console application from local.

configuring to run a console application from local


Step 2. Get snapshots

  • Get a snapshot after starting your application with dotMemory

Get a snapshot after starting your application with dotMemory

  • Then, write some bad code like instantiating an disposable object outside of the using scope (to stimulate your application to cause a memory leak)
  • Get snapshot again

step 2 Get snapshot after trying with bad code

  • Now, we have two snapshots before and after running a feature in your application.

 

Step 3. Compare snapshots
You can take more snapshots when monitoring the application. After that, select two snapshots that you want to compare and click on the compare button.

select two snapshots that you want to compare and click on the compare button


Step 4. Analyze the snapshots
In analysis windows, select the filter “Namespace”:

In analysis windows, select the filter “Namespace”
Then, you can see in the following window these elements:

  • The numbers of new objects
  • Surviving objects
  • Memory size of objects
    etc...

All is by “namespace” while your application is running.

see in the following window these elements - The numbers of new objects - Surviving objects Memory - Size of objects

 

Typical Memory Leak Situations

Subscribe and Unsubscribe Events

Event handling in .NET is a popular cause of memory leaks. The reason is that once you subscribe to an event, memory is allocated and it’s only released when you explicitly unsubscribe it. See the example below:

Event handling in .NET - a popular cause of memory leaks

After running and closing the above console app with dotMemory, you will see this:

result after running and closing the above console app with dotMemory
The ThresholdReached event is referenced in memory and can not be released after closing the application. To solve this problem, add code to unsubscribe the event.

The ThresholdReached event is referenced in memory and can not be released after closing the application

Next, run dotMemory again and you no longer see the ThresholdReached.

ThresholdReached is gone

Cache Big Data
Like the static variable, in some cases, we may catch data in memory but the application may run out of memory when caching big data. For example:

public static IDictionary<int, string> CacheData = new Dictionary<int, string>();
{
public string GetData(int id)
{
if (!CacheData.ContainsKey(id))
{
var result = GetDataFromDatabase(id);
CacheData.Add(id, result);
}

return CacheData[id];
}

private string GetDataFromDatabase(int id)
{
return "Text";
}
}


In this case, the method GetDataFromDatabase is expensive to call so I cache the data returned to a static variable. After a while, the memory will be eaten up and may cause the application crash. The solution can be to catch data to a catching server like Redis.

 

Forget to Dispose Unmanaged Memory

The garbage collector (GC) handles managed memory cleanup but it doesn’t cover unmanaged memory like database connection or file streams.

For example, your application creates a new connection to the database. After connecting and getting the data, you forget to close the connection. The GC doesn't manage the unmanaged memory allocated for that connection so it is left there as a memory leak.

Same issue can help with using file streams. See below example:

I add code to read a text file by stream reader and forget to close it

add code to read a text file by stream reader and forget to close it

After reading file, I get a snapshot from dotMemory as follows:

get a snapshot from dotMemory

In the Snapshot windows and Finalizable section, it shows the File Stream that I need to close.

in Snapshot windows and Finalizable section, it shows the File Stream that needs closing


Open FileStream object and see the details:

Open FileStream object and see the details


If I add the using statement like below, the issue is gone.

add the using statement, the issue is gone


In dotMemory, the stream reader no longer shows.

In dotMemory, the stream reader no longer shows

 

Using Disposable Objects

In class Counter, I have a method to get the total number of users from the database so I need a database connection object which is disposable so I have to implement an IDisposable interface in order to clean it up at the end.

public class Counter: IDisposable
{
private bool _disposed = false;
private SqlConnection _dbConnection;

public Counter()
{
_dbConnection = new SqlConnection();
}

public int GetTotalUsers()
{
_dbConnection.Open();
var command = new SqlCommand("SELECT COUNT(*) FROM [Users]", _dbConnection);
var userCount = (int) command.ExecuteScalar();
_dbConnection.Close();

return userCount;
}

protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;

if (disposing)
{
// Free any other managed objects here.
_dbConnection.Dispose();
}

// Free any unmanaged objects here.
_disposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~Counter()
{
Dispose(false);
}
}


Final Thoughts

dotMemory is a great tool for investigating and optimizing memory usage in applications. That is why I often use it in almost every application I’ve developed so far. I hope the above sample cases will be helpful to you and check out this resource to learn more about dotMemory.


 

References:
Find a Memory Leak, jetbrains.com, 2020.
Implement a Dispose method, doc.microsoft.com, 2020.
ENCYCLOPEDIA, pcmag.com.

 


About the Author

senior developer enlab software Vu Dao Hi, my name is Vu and I'm working as a Senior Developer at Enlab Software. I'm passionate about technology and aiming to advance my skill in .NET back-end coding. Outside work, I'd turn into a semi-pro photographer and capture moments in life with my camera. I hope to share more tech talk and foster meaningful conversations about .NET in the future.

 

Up Next

How to Secure Sensitive Data in The Configuration
October 13,2020 by Tan Nguyen
Introduction On the blog post “How to Configure .Net Core Environments With Practical Examples”, we shared...
How IIS Processes ASP.NET Core HTTP Request
September 30,2020 by Vinh Tran
Have you ever wondered what happens under the hood when you make an API call to...
Effective techniques for software engineer
September 25,2020 by Vinh Tran
Introduction Software development methodologies were introduced and practiced in every project using Waterfall which is the...
top-down-approaching-in-programming
September 11,2020 by Vinh Tran
Overview Writing code becomes much easier when requirements are broken down into actionable items with given...