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, if we don't code the right way, like using static variables, disposable objects, events, and threads, memory leaks can happen. When your app references an object that no longer needs to perform the desired task, it can make the garbage collector unable to reclaim the memory used, resulting in its performance degradation. 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, 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 the dotMemory application and config to run your application.

 

In my example, I am configuring to run a console application from the local.

 


Step 2. Get snapshots.

  • Get a snapshot after starting your application with dotMemory.

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

  • 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.


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


Then, you can see in the following window these elements:

  • The number of new objects
  • Surviving objects
  • The memory size of objects
    etc.

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

 

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:

 

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

The ThresholdReached event is referenced in memory and can not be released after closing the application. To solve this problem, add a code to unsubscribe from the event.

 

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

 

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 to crash. The solution can be to catch data to a caching server like Redis.

 

Forget to Dispose of Unmanaged Memory

The garbage collector (GC) handles managed memory cleanup, but it doesn’t cover unmanaged memory like a 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.

The same issue can help with using file streams. See the below example:

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



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

 

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


Open the FileStream object and see the details:


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


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

 

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

About the author

Vu Dao

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.
Frequently Asked Questions (FAQs)
What is dotMemory and how does it help in .NET programming?

dotMemory is a powerful profiling tool that helps detect and resolve memory leak issues in .NET applications. It assists developers in identifying unnecessary memory allocation by inspecting memory usage, understanding object relationships, and tracking down potential memory leaks, ensuring better application performance and resource management.

 

How can you find and analyze memory leaks using dotMemory?

To find and analyze memory leaks using dotMemory, you start by running the application with dotMemory and taking snapshots of memory usage at different stages. You can then compare these snapshots to identify objects that are not being released from memory. Detailed analysis includes looking into the number of new and surviving objects, memory size of objects, and categorizing them by namespace or class to pinpoint the source of memory leaks.

What are some typical situations where memory leaks occur, and how can dotMemory help resolve them?

Typical memory leak situations include improper event handling (subscribe/unsubscribe), caching big data in memory, forgetting to dispose of unmanaged resources, and improper use of disposable objects. dotMemory helps resolve these issues by providing insights into memory allocation and retention, allowing developers to trace the root cause of the leak and implement appropriate fixes, such as unsubscribing from events, managing cache size, or ensuring proper disposal of resources.

What are the general steps to detect and analyze memory leak issues using dotMemory?

The general steps include running your application with dotMemory, taking snapshots before and after running specific features, comparing these snapshots to identify differences in memory allocation, and analyzing the snapshots to identify new, surviving, or unnecessary objects. This process helps in identifying memory leaks and the objects responsible for them.

How does proper management of disposable objects and unmanaged resources affect memory usage, and how does dotMemory assist in this process?

Proper management of disposable objects and unmanaged resources is crucial to prevent memory leaks. Disposing of objects correctly ensures that unmanaged resources are released properly, preventing memory from being retained unnecessarily. dotMemory assists in this process by highlighting disposable objects and unmanaged resources that have not been released properly, allowing developers to identify and rectify issues related to resource management and disposal.

Up Next

July 05, 2024 by Dat Le
In the rapidly evolving world of software development, Big Data stands out as a transformative force....
June 27, 2024 by Dat Le
In today's rapidly evolving digital landscape, secure coding practices are paramount to safeguarding applications from a...
June 20, 2024 by Dat Le
In the rapidly evolving digital landscape, the role of User Interface (UI) and User Experience (UX)...
June 17, 2024 by Dat Le
In the dynamic world of software development, one element has emerged as crucial to success: User...

Can we send you our next blog posts? Only the best stuffs.

Subscribe