Question

When disposing a Monotouch.Dialog instance:

  • Custom UIBubbleMapElement elements are disposed by the GC;
  • For each disposed element, a custom UIBubbleMapCell also gets disposed by the GC;
  • But for all disposed cells, none of their custom UIBubbleMapView are being disposed.

To fix this problem, I started using the Mono Profiler application.

Mono profiler showing only a root reference.

The question is: Looking at a not disposed UIBubbleMapView instance inverse references image. How could I release this last reference and allow my custom view to be collected?

Finally, this is my UIBubbleMapCell dispose method:

protected override void Dispose (bool disposing) {

    bubbleMapView = null;

    System.Diagnostics.Debug.WriteLine ("############# {0} 'Dispose' {1}.", this, disposing ? "invoked directly" : "called by the garbage collector finalizer");

    base.Dispose (disposing);
}

And this is what I got printed into the console:

############# <UIBubblesViewController: 0x152427c0> 'Dispose' called by the garbage collector finalizer.
############# <UIBubbleMapCell: 0x152b6a40; baseClass = UITableViewCell; frame = (0 195; 320 38); autoresize = W; layer = <CALayer: 0x152c65c0>> 'Dispose' called by the garbage collector finalizer.
############# <UIBubbleMapCell: 0x1524aba0; baseClass = UITableViewCell; frame = (0 35; 320 38); autoresize = W; layer = <CALayer: 0x152038f0>> 'Dispose' called by the garbage collector finalizer.
############# <UIBubbleMapCell: 0x17c91710; baseClass = UITableViewCell; frame = (0 233; 320 116); autoresize = W; layer = <CALayer: 0x152cbb80>> 'Dispose' called by the garbage collector finalizer.
############# <UIBubbleMapCell: 0x1520b2c0; baseClass = UITableViewCell; frame = (0 108; 320 52); autoresize = W; layer = <CALayer: 0x17c2fc30>> 'Dispose' called by the garbage collector finalizer.

EDIT: Thanks Rolf for your answer.

First, I added the next code to the UITableViewCell Dispose method:

bubbleMapView.Dispose ();
bubbleMapView = null;

Although receiving the next message inside the console, Mono profiler still presenting the object as not collected. Same Images as before.

 ############# <UIBubbleMapView: 0x154af370; frame = (0 0; 1 1); layer = <CALayer: 0x154af0e0>> 'Dispose' invoked directly.

When running in the intruments App, I can see its reference count bigger than one.

Visible memory leak.

In the image there is a UIBubbleTextView instance, but it behaves exactly in the same way as the UIBubbleMapView instances.

My UIBubbleMapView holds some other views. This is the profiler information when the inverse reference isn't checked. Are there some tricks to handle with these kind of subviews?

No inverse references

Was it helpful?

Solution

The <Other Root> is usually a GCHandle Xamarin.iOS uses internally to keep the managed object alive until the corresponding native object is freed. One way of breaking this link is to call Dispose on the object (you don't mention calling Dispose on UIBubbleMapView), in which case the managed object will be collected by the GC (unless it's referenced by other managed code of course).

Most likely there is some other native code holding a reference to this UIBubbleMapView instance, but finding out exactly what is going on you need to profile using the Allocation instrument in Instruments (enabling ref count tracking to track down exactly which code is retaining the object).

Update

Until you call Dispose on the managed object, the managed object will retain the native object [1]. This means that if the retain count is > 1, then there are additional native retains to that object (it also means that once you've called Dispose on the object, the remaining references are all native). Note that at this point the managed object might be collected by the GC, so you can't track the (native) object by using HeapShot anymore, you must use Instruments.

Hint: if you enable the right side-bar in Instruments, you will get a stack trace of each retain/release call. This is very helpful in tracking down who retains an object.

[1] Xamarin.iOS will also release the reference the managed object has once the retain count reaches one (and the GC has determined that the managed object isn't referenced from other managed code).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top