Unit Testing and Memory Profiling: Can They Be Combined?

Memory profilers can hardly be called an “everyday tool.” Typically, developers start thinking about profiling their product closer to its release. This approach may work fine until some last-minute issue like a leak or huge memory traffic crushes all your deadlines. The proactive approach would be to profile your app’s functionality on a daily basis, but who’s got the resources to do that? Well, we think there may be a solution.

If you employ unit testing in your development process, it is likely that you regularly run a number of tests on app logic. Now imagine that you can write some special “memory profiling” tests, e.g. a test that identifies leaks by checking memory for objects of particular type, or a test that tracks memory traffic and fails in case the traffic exceeds some threshold. This is exactly what dotMemory Unit framework allows you to do. The framework is distributed as a NuGet package and can be used to perform the following scenarios:

  • Checking memory for  objects of a certain type.

  • Checking memory traffic.

  • Getting the difference between memory snapshots.

  • Saving memory snapshots for further investigation in dotMemory (a standalone .NET memory profiler from JetBrains).

In other words, dotMemory Unit extends your unit testing framework with the functionality of a memory profiler.

IMPORTANT: dotMemory Unit is currently in the EAP (Early Access Program) stage. Please use it for evaluation purposes only!

How It Works

  • dotMemory Unit is distributed as a NuGet package installed to your test project:
    PM> Install-Package JetBrains.DotMemoryUnit -pre

  • dotMemory Unit requires ReSharper unit test runner. To run tests that use dotMemory Unit, you should have either dotCover 3.1 EAP or ReSharper 9.1 EAP05 installed on your system.

  • After you install the dotMemory Unit package, ReSharper’s menus for unit tests will include an additional item, Run Unit Tests under dotMemory Unit. In this mode, the test runner will execute dotMemory Unit calls as well as ordinary test logic. If you run a test the ‘normal’ way (without dotMemory Unit support), all dotMemory Unit calls will be ignored.

    Unit Tests Menu

  • dotMemory Unit works with all of the unit-testing frameworks supported by ReSharper’s unit test runner including MSTest and NUnit.

  • A standalone launcher for integrating with CI systems like JetBrains TeamCity is planned for future releases.

Now let’s take a look at some examples to better understand what dotMemory Unit does.

Example 1: Checking for Specific Objects

Let’s start with something simple. One of the most useful cases can be finding a leak by checking memory for objects of a specific type.

GetObjects Assertion

  1. A lambda is passed to the Check method of the static dotMemory class. This method will be called only in case you run the test using Run test under dotMemory Unit.

  2. The memory object passed to the lambda contains all memory data for the current execution point.

  3. The GetObjects method returns a set of objects that match the condition passed in another lambda. This line slices the memory by leaving only objects of the Foo type. The Assert expression asserts that there should be 0 objects of the Foo type.
    Note that dotMemory Unit does not force you to use any specific Assert syntax. Simply use the syntax of the framework your test is written for. For example, the line in the example uses NUnit syntax but could be easily updated for MSTest:
    MSTest Assertion

With dotMemory Unit you can select a set of objects by almost any condition, get the number of objects in this set and their size, and use these data in your assertions.
In the following example, we check for objects in the large object heap:

Checking for Specific Objects


Example 2: Checking Memory Traffic

The test for checking memory traffic is even simpler. All you need do to is mark the test with the AssertTraffic attribute. In the example below, we assert that the amount of memory allocated by all the code in TestMethod1 does not exceed 1,000 bytes.

AssertTraffic Attribute Example

Example 3: Complex Scenarios for Checking Memory Traffic

If you need to get more complex information about memory traffic (say, check for traffic of objects of a particular type during some specific time interval), you can use a similar approach to the one from the first example. The lambdas passed to the dotMemory.Check method slice and dice traffic data by various conditions.

Check Traffic with Traffic Type

  1. To mark time intervals where memory traffic can be analyzed, use checkpoints created by dotMemory.Check (as you probably guessed, this method simply takes a memory snapshot).

  2. The checkpoint that defines the starting point of the interval is passed to the GetTrafficFrom method.
    For example, this line asserts that the total size of objects implementing the IFoo interface created in the interval between memoryCheckPoint1 and memoryCheckPoint2 is less than 1,000 bytes.

  3. You can get traffic data for any checkpoint that was set earlier. Thus, this line gets traffic between the current dotMemory.Check call and memoryCheckPoint2.

Example 4: Comparing Snapshots

Like in the ‘standalone’ dotMemory profiler, you can use checkpoints not only to compare traffic but for all kinds of snapshot comparisons. In the example below we assert that no objects from the MyApp namespace survived garbage collection in the interval between memoryCheckPoint1 and the second dotMemory.Check call.

Compare Snapshots


dotMemory Unit is very flexible and allows you to check almost any aspect of app memory usage. Use “memory” tests in the same way as unit tests on app logic:

  • After you manually find an issue (such as a leak), write a memory test that covers it.

  • Write tests for proactive testing – to ensure that new product features do not create any memory issues, like objects left in memory or large traffic.

Thanks for reading and don’t hesitate to try dotMemory Unit EAP on your own! It’s absolutely free, and the only requirement is ReSharper or dotCover installed on your machine.

This entry was posted in dotMemory Tips&Tricks, How-To's, News and Events and tagged , , . Bookmark the permalink.

27 Responses to Unit Testing and Memory Profiling: Can They Be Combined?

  1. MichaelD! says:

    Wow! Pretty awesome. :)

  2. Cape says:

    If the ReSharper test runner is required, how can we automate this in CI? Will there be a TeamCity runner?

  3. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1813

  4. Pingback: Dew Drop – March 5, 2015 (#1968) | Morning Dew

  5. Wow, I am sure I will be using this soon.

  6. Lior Tal says:

    Very interesting.

    I wonder how you are querying the information about objects in memory, and whether the test method and classes it instantiates have any effect on this.

    • Alexey Totin says:

      dotMemory Unit is based on the standalone dotMemory profiler – it is almost the same product but without the UI. Talking about the impact. It is minimal, though, of course you will be able to find some dM Unit objects in memory (if you set such a goal).

      • Ed Pavlov says:

        I would say dotMemory Unit is not based on standalone dotMemory but both of them are based on dotMemory Core assemblies. The difference is not so big but still :)

    • Mike-EEE says:

      OK! I have taken the plunge here and I am trying this out with xUnit. This question pretty much consists of my first thoughts and findings. If I run an empty test, it appears that out of the gate 48 objects are created. Is this correct/expected? I also *really* like how there appears to be a snapshot created before the test runs and after it runs, if that is correct? So it is just a matter of creating snapshots during the run to compare to the before and after states. Pretty awesome. :)

  7. Pingback: Automate The Planet #6 « Automate The Planet

  8. Orion says:


    I’m new to using profiling tools, & I’m trying to use it on a large code base I’m new to… I was given a PerfMon dump where the “Promoted Memory from Gen 0” is suspected of being too large. Would this tool be able to provide me with data related to that metric?


    – O8

  9. Alex Popin says:

    Уважаемый Алексей,

    я заядлый копипастер из страны Оз и было б здорово, если бы я не был так печален перепечатывая каждый раз лямбду вручную из вашего блогопоста.

  10. Pingback: JetBrains 3rd Annual Hackathon: New-Generation Debugger Grabs 1st Place | JetBrains Company Blog

  11. Mark says:

    Are you going to release something similar for Java?

  12. Pingback: Make profiling a part of continuous integration (.NET) | JetBrains TeamCity Blog

  13. Mendel Monteiro-Beckerman says:

    It seems a page referred to by an DotMemoryUnit exception has dissapeared, namely https://www.jetbrains.com/dotmemory/unit/help/Turning_On_Off_Collecting_of_Allocation_Data.html

    Any tips getting the memory traffic analysis to work?

  14. Mendel Monteiro-Beckerman says:

    Is there a way to get the checkpoints without allocating any memory? When I inspect the memory traffic between two checkpoints I see dead objects that are created during the dotMemoryUnit.Check() method.

    I’m trying to check that a certain part of my code does not allocate at all and thus this makes it more difficult than it should be.

    • Ed Pavov says:

      Unfortunatelly, for now there is no way to filter out objects allocated in test method and by dotMemory Unit itself. There is a ticket in our bug tracker, you could vote and follow it up.

      • Mike-EEE says:

        Bummer. This sort of addresses my question above. Unfortunately that issue/ticket is unaccessible, so I can’t vote on it. It does seem odd that objects are created without having any code whatsoever in test cases.

        Also, it seems there are wildly different reported objects that are created for different tests. Using a clean project with an single/simple xUnit reference, a test run comprised of two empty tests both fail with an [AssertTraffic( AllocatedObjectsCount = 0 )] applied to it. The first fails with 48 created objects (seems like a bug), and the second test fails with 1,114 objects (bigger bug!).

Leave a Reply

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