Advanced course in dotMemory Unit

Some of you know one of our most recently released .NET products: dotMemory Unit, a unit testing framework that helps check your .NET code for memory issues.

In a nutshell, dotMemory Unit adds memory profiling to your unit testing framework. With dotMemory Unit, you can write tests that check your code for all kinds of memory issues, protect already fixed leaks from regression, and use the TDD approach when writing memory-consuming algorithms.

How is all this implemented? In this post, we would like to shed some light on the internals of dotMemory Unit.

If you need an overview of dotMemory Unit before diving in, start with this blog post that explains the basics, then take a look at some usage examples, or refer to online help.

Test methods

It’s all about tests. First of all, dotMemory Unit tries to detect which of your methods are tests. Why does it need that?

First, because you might want to decorate your test with a special attribute to tell dotMemory Unit what to do. For example, you can ask it to check the amount of memory traffic in a test with [AssertTraffic(AllocatedSizeInBytes = 300000)].

The second reason is that it needs to know exactly when each test starts and ends in order to save a memory snapshot if a test fails on a “memory” assertion.

For most unit testing frameworks, namely MSTest, NUnit, xUnit.net, MbUnit and csUnit, dotMemory Unit detects test methods automatically by injecting its calls into the beginning and the end of all tests.

Even if your unit testing framework of choice is not on the list of frameworks supported out of the box, you still can use dotMemory Unit. You can find more details on how to do this later in this post.

Why use lambdas in dotMemory.Check()

In order to get memory state and make assertions you should write something like this in your test:

Why do we need a lambda as an argument of the dotMemory.Check() method to do such a simple thing? There are several reasons for this.

First, you don’t need to write a special “memory test” to detect memory issues, it is enough to add an assertion on memory state to your regular unit test.[1] Such a test (checking both memory and logic) can be run under dotMemory Unit or as an ordinary test. In the latter case, the test will fail as there’s no valid memory data. And this is exactly why we need dotMemory.Check(): the lambda passed into this method will not be called at all if tests are running without dotMemory Unit.[2]

The second reason of having a lambda as an argument in dotMemory.Check() is to know whether a test failed on checking memory state or on checking business logic: it is useful to have snapshots from tests failed on checking memory to go straight to memory problems.


  1. There is an example of such tests (see RemovePetriDish test). It is a normal unit test, checking that there are no items in a collection after removing the last item, but it also checks that there are no items retained in memory, which means no memory leaks.
  2. By default, if dotMemory.Check() is called without dotMemory Unit, it will fail. If you need the test to pass by ignoring dotMemory.Check(), mark the method, class or assembly with the attribute [DotMemoryUnit(FailIfRunWithoutSupport = false)]

Using dotMemoryApi instead of dotMemory.Check()

dotMemory.Check() is suitable for most common simple cases but if you don’t like its syntax or find it unsuitable for any other reason, rest assured there’s an alternative available.

In the following example, dotMemory.Check() looks out of place when memory usage data is gathered during the test and checked just once in the end:

What is the other option? At the heart of dotMemory Unit, there’s the dotMemoryApi class, which is quite simple:

The above example can be rewritten using dotMemoryApi as follows:

But how do we tell dotMemory Unit to save snapshots if a test failed on a memory assertion? Of course, you can use the “save on any fail” auto-saving strategy, but it is not always convenient. Let’s write a single method that uses a lambda as well but looks not as awkward as in the initial example…

…and rewrite the assertion block from our last example:

This call will save a workspace with memory snapshots in case of a failure. As an added bonus, it just looks neat, doesn’t it?

Let’s take a closer look at DotMemoryUnitController and see how it can be useful when dealing with testing frameworks that aren’t supported out of the box.

Unsupported testing frameworks

What should you do if your favorite unit testing framework is not supported by dotMemory Unit out of the box? The answer is, adapt it manually! In fact, all you need is to tell dotMemory Unit where your test method starts, ends and fails. All this can be done using a single DotMemoryUnitController class:

To make it easier and more elegant, you can write your own wrapper or use this one. At the end, your test will look like this (even attributes will work fine):

Although DotMemoryUnitController is mostly designed for unsupported testing frameworks, it also can be used in combination with dotMemoryApi to achieve behavior similar to the dotMemoryUnit.AssertBlock() example above.

More ways to tune

There are many ways how you can fine-tune dotMemory Unit to your liking. For example, if you don’t like the lambda in the GetObjects() method, you can write something like this:

and then completely avoid lambdas in your tests:

Also, don’t miss QueryBuilder. This powerful tool allows creating reusable queries to make your tests more maintainable. For example, we can rewrite one of the examples from this article using QueryBuilder to avoid code duplication:

If you’re using core classes dotMemoryApi, DotMemoryUnitController and QueryBuilder and have a general idea of how dotMemory Unit works inside, you can customize almost everything and write your perfect framework.

Whether you want to go that far or you use the default framework, dotMemory Unit will help you replace time-consuming manual profiling with automated memory tests.

This entry was posted in How-To's and tagged , . Bookmark the permalink.

5 Responses to Advanced course in dotMemory Unit

  1. Mike-EEE says:

    Man the greatness continues. :)

    I am really impressed with R# Ultimate. I mean… I have had my nose in it for over a decade but *seriously* in it for the past six months with dotTrace and unit testing in general (when it works :) ). I have learned so much and I am truly appreciative of your amazing suite of tools. Now I am moving into memory management and have been blown away by your series of articles (starting here: http://blog.jetbrains.com/dotnet/2014/07/10/unusual-ways-of-boosting-up-app-performance-boxing-and-collections/ ) around this (truly, Heap Allocation Viewer should be a standard feature of R#!).

    Anyways, I do have an issue out on your YouTrack (https://youtrack.jetbrains.com/issue/DMRY-3713 ) but I wanted to verify it here and also see if there is something that I am missing. Is it possible to take a snapshot with dotMemory Unit and then be able to load it with the dotMemory viewer? Right now I am having to use VS’s memory profiler to take snapshots and by the looks of it, I am missing out on quite a bit by not being able to use dotMemory. :) It seems by the code samples that the “snapshots” are strictly in-memory and cannot be saved to disk. Is this correct?

    I do see a “SaveCollectedData”… does this save a dotMemory-loadable file? That would be a start. Ideally, it would be awesome to take a snapshot with dotMemory Unit (where it saves it to a managed, well-known R# Ultimate location) and then have it list a launch link in dotCover to view it. Hey, did I just think of yet another idea? :) :) :)

  2. Pingback: Dew Drop – June 1, 2016 (#2263) | Morning Dew

  3. Yves V. says:

    Entirely agree with Mike,

    I bought my personal license several years ago, I was a real fan of your products, it always helps me to do better code, to see small details that many developers pass over, but now with that… I’m really impressed!

    Thank you!

Leave a Reply

Your email address will not be published. Required fields are marked *