Aspects and Garbage Collection

Earlier today I wrote about an Assert method which can be used in unit tests to check whether or not an object is collected during Garbage Collection (GC). I wrote this method because I was suspicious about a certain PostSharp Aspect I just implemented. The aspect works great, and I’ll surely write about it later; however, since it’s an aspect which is meant to be applied on an entire assembly by using multicasting, I thought twice before calling it a day.

After being skeptical and writing unit tests to ensure my IsGarbageCollected() method was actually working as expected, I came to the unfortunate conclusion that my aspects were keeping my objects in memory!

It only makes sense really; why wouldn’t aspects be able to keep objects alive? It might not be the first thing you think about, but hopefully this post makes you aware of the hidden dangers. As an example I’ll show you a very basic aspect, and how to fix it.

[Serializable]
public class SampleAspect : IInstanceScopedAspect
{
	[NonSerialized]
	object _instance;

	public object CreateInstance( AdviceArgs adviceArgs )
	{
		_instance = adviceArgs.Instance;
		return MemberwiseClone();
	}

	public void RuntimeInitializeInstance()	{ }
}

As any other memory leak, it suffices to leave one reference lying around to an object, preventing the GC from collecting it. There are two mistakes in the previous code, can you find them?

The first one was most obvious to me. _instance is holding a reference to the object, keeping it alive. Luckily .NET offers us an easy solution, WeakReference. A WeakReference references an object while still allowing that object to be reclaimed by garbage collection.

[Serializable]
public class SampleAspect : IInstanceScopedAspect
{
	[NonSerialized]
	WeakReference _instance;

	public object CreateInstance( AdviceArgs adviceArgs )
	{
		_instance = new WeakReference( adviceArgs.Instance );
		return MemberwiseClone();
	}

	public void RuntimeInitializeInstance()	{ }
}

However, Gael was kind enough to quickly point out this wasn’t the real issue. PostSharp uses prototypes to initialize its aspects. An existing prototype object is cloned to create new aspects. The CreateInstance() method is called on the prototype object, and you are expected to return a new aspect. The real error in my code was I was setting _instance on the prototype, while I should be setting it on the cloned object instead. The prototype object is kept in memory by PostSharp, and as a result the last created object was also held in memory. Not a big issue, but the following implementation is a bit cleaner.

[Serializable]
public class SampleAspect : IInstanceScopedAspect
{
	[NonSerialized]
	object _instance;

	public object CreateInstance( AdviceArgs adviceArgs )
	{
		var newAspect = (InitializeEventHandlerAspect)MemberwiseClone();
		newAspect._instance = adviceArgs.Instance;

		return newAspect;
	}

	public void RuntimeInitializeInstance()	{ }
}

No need to use WeakReference any longer, although I imagine it might still be useful in other scenarios.

Author: Steven Jeuris

I have a PhD in Human-Computer Interaction and am currently working both as a software engineer at iMotions and as a postdoc at the Technical University of Denmark (DTU). This blend of research and development is the type of work which motivates and excites me the most. Currently, I am working on a distributed platform which enables researchers to conduct biometric research 'in the wild' (outside of the lab environment). I have almost 10 years of professional software development experience. Prior to academia, I worked for several years as a professional full-stack software developer at a game development company in Belgium: AIM Productions. I liked the work and colleagues at the company too much to give up entirely for further studies, so I decided to combine the two. In 2009 I started studying for my master in Game and Media Technology at the University of Utrecht in the Netherlands, from which I graduated in 2012.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s