Category Archives: dotMemory Unit

Where have you been hiding dotMemoryUnit?

As a subscriber to all the JetBrains tools, I’m surprised that I didn’t know about dotMemoryUnit until it was mentioned on a recent episode of dotnetrocks. I’ve looked into memory type unit testing in the past as it’s an area (along with performance) that I find particularly of interest as part of a CI build.

So here it is MONITOR .NET MEMORY USAGE WITH UNIT TESTS.

Prerequisites

Simply add the NuGet package JetBrains.DotMemoryUnit to your test project and you’ll get the library for writing dotMemory test code, if you want to run dotMemory unit tests from the command line (or from your build/CI server) you’ll need to download the runner from https://www.jetbrains.com/dotmemory/unit/.

To run the command line test runner you’ll need to run dotMemoryUnit.exe passing in your test runner application and the DLL to be tested through dotMemoryUnit. For example

dotMemoryUnit "C:\Program Files (x86)\NUnit 2.6.3\bin\nunit-console.exe" MyDotMemoryTests.dll

If you’re using Resharper the test runner supports dotMemory Unit, but you’ll need to select the option Run under dotMemory Unit or you’ll see the message

DotMemoryUnitException : The test was run without the support for dotMemory Unit. To safely run tests with or without (depending on your needs) the support for dotMemory Unit:

in Resharper’s test runner output window.

Getting started

The key thing to bare in mind is that dotMemoryUnit is not a unit testing framework and not an assertion framework, so you’ll still write NUnit, xUnit, MSTest etc. (unsupported test frameworks can be integrated with dotMemoryUnit, see Working with Unsupported Unit Testing Frameworks) code and you can still use the assertions with these libraries, or the likes of Should, Shouldly, FluentAssertions etc.

dotMemoryUnit simply allows us to add code to investigate memory usage, so here’s an example

[Test]
public void FirstTest()
{
   var o = new MyObject();

   dotMemory.Check(memory =>
      Assert.That(
         memory.GetObjects(
            where => where.Type.Is<MyObject>())
         .ObjectsCount, Is.EqualTo(0)));

   GC.KeepAlive(o);
}

In this example, we create an object and then use dotMemory to carry out a memory “check”. The dotMemory.Check call is a checkpoint (or snapshot) and returns a MemoryCheckpoint object which can be used to compare two checkpoints and/or we can carry out a query against the memory within the lambda in the checkpoint call.

Here, you can see, we get the memory then search of objects of type MyObject. We then assert whether this object count is zero. In the above it’s probable that the object has not been disposed of and hence this test will fail, however we have the GC.KeepAlive(o) in place to ensure that the object is not garbage collected during the test run.

See Checking for Objects

Beware that when running dotMemoryUnit, a .dmw file is created (by default) for failing tests and these are placed in your %USERPROFILE%\AppData\Local\Temp\dotMemoryUnitWorkspace folder. There is an auto delete policy when running dotMemoryUnit but these files are often MB’s in size. We can change the default locaiton on a per test basis using the DotMemoryUnitAttribute, i.e.

Note: The dmw file is viewable for the dotMemory application which is part of the JetBrains suite of applications.

[DotMemoryUnit(Directory = "c:\\Temp\\dotMemoryUnit")]
public void EnsureMemoryFreed()
{
// asserts
}

We’ve seen the use of the dotMemory.Check method. We can also use the dotMemoryApi class which gives a slightly different interface, for example the following code creates two snapshots and then checks what objects of type MyObject were created between the snapshots, for example

[Test]
public void AllocateFourMyObjects()
{
   var snap1 = dotMemoryApi.GetSnapshot();

   var f1 = new MyObject();
   var f2 = new MyObject();
   var f3 = new MyObject();
   var f4 = new MyObject();

   var snap2 = dotMemoryApi.GetSnapshot();

   Assert.That(
      snap2.GetObjects(w => w.Type.Is<MyObject>()).ObjectsCount -
      snap1.GetObjects(w => w.Type.Is<MyObject>()).ObjectsCount, 
      Is.EqualTo(4));
}

We can also use the AssertTrafficAttribute (Note: this seemed very slow via Resharper’s GUI whereas the console app was much faster). In a similar way to the above, although in this example we’re saying assert that the allocated object count of types MyObject does not exceed 4, i.e. in the previous code we states that we expect exactly 4 allocations, so be aware the difference here.

[
Test,
AssertTraffic(AllocatedObjectsCount = 4, Types = new [] { typeof(MyObject)})
]
public void AllocateFourMyObjects()
{
   var f1 = new MyObject();
   var f2 = new MyObject();
   var f3 = new MyObject();
   var f4 = new MyObject();
}

Finally, we can also use snapshot and the dotMemoryApi.GetTrafficBetween method do so something similar to the last two examples

[
Test, DotMemoryUnit(CollectAllocations = true)
]
public void AllocateFourMyObjects()
{
   var snap1 = dotMemoryApi.GetSnapshot();

   var f1 = new MyObject();
   var f2 = new MyObject();
   var f3 = new MyObject();
   var f4 = new MyObject();

   var snap2 = dotMemoryApi.GetSnapshot();

   var traffic = dotMemoryApi.GetTrafficBetween(snap1, snap2);
   var o = traffic.Where(w => w.Type.Is<MyObject>());
   Assert.AreEqual(4, o.AllocatedMemory.ObjectsCount);
}

To use memory allocations we need to set the DotMemoryUnitAttribute CollectAllocations to true. For the AssertTrafficAttribute this happens automatically.

That’s if for now. Go and experiment.

References

dotMemoryUnit Help