A have a complex control with many subviews. When it has to rerender, it disposes of all of the subviews and rebuilds. There is always significant memory loss with each iteration.
(I'm aware of UIView reuse; that doesn't fix the underlying problem.)
Since I am careful to dispose of and dereference every view I create, I expect there to be a negligible overall effect between iterations.
To see if in fact it is possible, I made a test project to benchmark the loss. In the following example
public void Demonstrate ()
{
while(true)
{
Console.WriteLine("[Memory] UIView start: {0}", GC.GetTotalMemory(false));
for (int i = 0; i < 1000; i++)
{
var view = new UIView();
View.AddSubview(view);
view.RemoveFromSuperview();
view.Dispose();
}
Console.WriteLine("[Memory] UIView end: {0}", GC.GetTotalMemory(false));
GC.Collect();
Thread.Sleep(2000); // GC runs on another thread. Give it some time.
Console.WriteLine("[Memory] UIViewSubclass start: {0}", GC.GetTotalMemory(false));
for (int i = 0; i < 1000; i++)
{
var sub = new UIViewSubclass();
View.AddSubview(sub);
sub.RemoveFromSuperview();
sub.Dispose();
}
Console.WriteLine("[Memory] UIViewSubclass end: {0}", GC.GetTotalMemory(false));
GC.Collect();
Thread.Sleep(2000); // GC runs on another thread. Give it some time.
}
}
class UIViewSubclass : UIView
{
}
Here is the output.
2014-02-05 19:09:08.366 UIViewSubclassingMemoryLeak[2547:60b] [Memory] Baseline: 67584
2014-02-05 19:09:08.370 UIViewSubclassingMemoryLeak[2547:60b] [Memory] Tap to start.
2014-02-05 19:09:11.725 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 92160
2014-02-05 19:09:12.014 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 124928
2014-02-05 19:09:14.019 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 95232
2014-02-05 19:09:14.307 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 286720
2014-02-05 19:09:16.312 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 250880
2014-02-05 19:09:16.595 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 326656
2014-02-05 19:09:18.601 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 270336
2014-02-05 19:09:18.885 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 434176
2014-02-05 19:09:20.891 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 399360
2014-02-05 19:09:21.175 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 530432
2014-02-05 19:09:23.182 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 472064
2014-02-05 19:09:23.468 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 691200
2014-02-05 19:09:25.476 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 603136
2014-02-05 19:09:25.748 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 835584
2014-02-05 19:09:27.757 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 718848
2014-02-05 19:09:28.048 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 776192
2014-02-05 19:09:30.057 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 766976
2014-02-05 19:09:30.347 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 863232
2014-02-05 19:09:32.357 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 845824
2014-02-05 19:09:32.645 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 931840
2014-02-05 19:09:34.656 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 903168
2014-02-05 19:09:34.930 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1081344
2014-02-05 19:09:36.941 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 969728
2014-02-05 19:09:37.235 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1188864
2014-02-05 19:09:39.246 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1139712
2014-02-05 19:09:39.519 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1332224
2014-02-05 19:09:41.532 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1213440
2014-02-05 19:09:41.825 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1292288
2014-02-05 19:09:43.838 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1258496
2014-02-05 19:09:44.115 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1427456
2014-02-05 19:09:46.128 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1316864
2014-02-05 19:09:46.411 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1537024
2014-02-05 19:09:48.425 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1391616
2014-02-05 19:09:48.721 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1673216
2014-02-05 19:09:50.737 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1497088
2014-02-05 19:09:51.017 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1764352
2014-02-05 19:09:53.033 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1586176
2014-02-05 19:09:53.306 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1736704
2014-02-05 19:09:55.323 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1627136
2014-02-05 19:09:55.603 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1829888
2014-02-05 19:09:57.620 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1684480
2014-02-05 19:09:57.894 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1835008
2014-02-05 19:09:59.912 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1724416
2014-02-05 19:10:00.196 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 1928192
2014-02-05 19:10:02.215 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1777664
2014-02-05 19:10:02.487 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 1933312
2014-02-05 19:10:04.507 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1822720
2014-02-05 19:10:04.789 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 2024448
2014-02-05 19:10:06.808 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 1872896
2014-02-05 19:10:07.084 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 2028544
2014-02-05 19:10:09.104 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 1917952
2014-02-05 19:10:09.412 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 2452480
2014-02-05 19:10:11.433 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 2294784
2014-02-05 19:10:11.708 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 2463744
2014-02-05 19:10:13.730 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 2353152
2014-02-05 19:10:14.012 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 2572288
2014-02-05 19:10:16.034 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 2424832
2014-02-05 19:10:16.309 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 2577408
2014-02-05 19:10:18.332 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 2466816
2014-02-05 19:10:18.616 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 2669568
2014-02-05 19:10:20.639 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 2524160
2014-02-05 19:10:20.914 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 2674688
2014-02-05 19:10:22.938 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 2564096
2014-02-05 19:10:23.220 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 2767872
2014-02-05 19:10:25.245 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 2623488
2014-02-05 19:10:25.558 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 3035136
2014-02-05 19:10:27.585 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 2793472
2014-02-05 19:10:27.868 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 3126272
2014-02-05 19:10:29.896 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 2918400
2014-02-05 19:10:30.171 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 3064832
2014-02-05 19:10:32.199 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 2955264
2014-02-05 19:10:32.481 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 3158016
2014-02-05 19:10:34.510 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 3015680
2014-02-05 19:10:34.784 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 3163136
2014-02-05 19:10:36.814 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 3052544
2014-02-05 19:10:37.097 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 3256320
2014-02-05 19:10:39.127 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView start: 3115008
2014-02-05 19:10:39.404 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIView end: 3261440
2014-02-05 19:10:41.435 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass start: 3150848
2014-02-05 19:10:41.717 UIViewSubclassingMemoryLeak[2547:60b] [Memory] UIViewSubclass end: 3352576
I am guessing that this is related to this comment in the docs; but it doesn't demonstrate any kind of solution:
AddSubview Creates a GCHandle
The call to container.AddSubview will increase the reference count on the unmanaged MyView instance. When this happens, the Xamarin.iOS runtime creates a GCHandle to keep the MyView object in managed code alive, because there is no guarantee that any managed objects will keep a reference to it. In fact, as far as the C# code is concerned; the object would be gone after the AddSubview call were it not for the GCHandle.