Is this a bug in MonoTouch GC?

This is an unfortunate side-effect of MonoTouch (who is garbage collected) having to live in a reference counted world (ObjectiveC).

There are a few pieces of information required to be able to understand what’s going on:

  • For every managed object (derived from NSObject), there is a corresponding native object.
  • For custom managed classes (derived from framework classes such as UIButton or UIView), the managed object must stay alive until the native object is freed [1]. The way it works is that when a native object has a reference count of 1, we do not prevent the managed instance from getting garbage collected. As soon as the reference count increases above 1, we prevent the managed instance from getting garbage collected.

What happens in your case is a cycle, which crosses the MonoTouch/ObjectiveC bridge and due to the above rules, the GC can’t determine that the cycle can be collected.

This is what happens:

  • Your ChildViewController has a sayHiButton. The native ChildViewController will retain this button, so its reference count will be 2 (one reference held by the managed CustomButton instance + one reference held by the native ChildViewController).
  • The TouchUpInside event handler has a reference to the ChildViewController instance.

Now you see that the CustomButton instance will not be freed, because its reference count is 2. And the ChildViewController instance will not be freed because the CustomButton’s event handler has a reference to it.

There are a couple of ways to break the cycle to fix this:

  • Detach the event handler when you no longer need it.
  • Dispose the ChildViewController when you no longer need it.

[1] This is because a managed object may contain user state. For managed objects which are mirroring a corresponding native object (such as the managed UIView instance) MonoTouch knows that the instance can not contain any state, so as soon as no managed code has a reference to the managed instance, the GC can collect it. If a managed instance is required at a later stage, we just create a new one.

Leave a Comment