Bug 25257 - [All platforms] Setting ListView.ItemsSource creates references that cannot be garbage collected
Summary: [All platforms] Setting ListView.ItemsSource creates references that cannot b...
Status: RESOLVED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 1.4.3
Hardware: PC Mac OS
: Highest major
Target Milestone: ---
Assignee: Eric Maupin
URL:
Depends on:
Blocks:
 
Reported: 2014-12-11 00:17 UTC by Brendan Zagaeski (Xamarin Team, assistant)
Modified: 2016-03-25 18:58 UTC (History)
7 users (show)

Tags: listview memory RA AC
Is this bug a regression?: ---
Last known good build:


Attachments
Test case (111.13 KB, application/zip)
2014-12-11 00:17 UTC, Brendan Zagaeski (Xamarin Team, assistant)
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Brendan Zagaeski (Xamarin Team, assistant) 2014-12-11 00:17:18 UTC
Created attachment 9025 [details]
Test case

Setting ListView.ItemsSource creates references that cannot be garbage collected. This problem might happen with other `INotifyPropertyChanged` properties too.

I observed the problem on both Android and iOS. I haven't tested Windows Phone.


Bug 25052 might be closely related.


## Steps to reproduce

1. Build the attached test case in the Debug configuration for Android or iOS.

This test case is based on the "LabelledSectionsList" sample [1]. The only change is an extra button that allows the user to re-set the list's `ItemsSource`:

> void HandleClicked(object sender, EventArgs e)
> {
>     var newList1 = SetupList();
>     var newList2 = SetupList();
> 
>     for (var i = 0; i < 400; i++)
>     {
>         list.ItemsSource = i % 2 > 0 ? newList1 : newList2;
>     }
>
>     GC.Collect();
>     GC.WaitForPendingFinalizers();
> }

> [1] https://github.com/xamarin/xamarin-forms-samples/tree/master/LabelledSectionsList



2. Run the app with heapshot profiling enabled:

- For iOS devices or simulators, use the "Project -> Profile - Mono..." menu command in Xamarin Studio on Mac.

- For Android devices or emulators, use `adb shell setprop debug.mono.profile log:heapshot` as described on [2].
> [2] http://stackoverflow.com/questions/19125266/how-to-take-heap-snapshot-of-xamarin-androids-mono-vm/19126051#19126051



3. Tap the "Reload list" button at the top of the window once and wait for the operation to complete.



4. For iOS, take a snapshot using the HeapShot app. For Android, just wait 10 seconds so there will be an easily identifiable space between the automatic GC-triggered snapshots.



5. Repeat steps 3 + 4.



## Results

The total managed size of the app increases by about 5 megabytes after each press of the button. I suspect that pressing the button repeatedly would eventually crash the app. But each button press takes a long time to complete, so I haven't tested that.


### Top of the heapshot after step 4 on Android

> Heap shot 1 at 17.625 secs: size: 5215096, object count: 125217, class count: 373, roots: 0
>      Bytes      Count  Average Class name
>     645040      16126       40 Xamarin.Forms.BindableObject.BindablePropertyContext (bytes: +18584, count: +464)
>     562464      10044       56 System.ComponentModel.PropertyChangedEventHandler (bytes: -200368, count: -3578)
>     450688       8048       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +12992, count: +232)
>     450352       8042       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +12992, count: +232)


### Top of the heapshot after step 5 on Android

> Heap shot 7 at 36.985 secs: size: 10154000, object count: 245489, class count: 376, roots: 0
>      Bytes      Count  Average Class name
>    1286960      32174       40 Xamarin.Forms.BindableObject.BindablePropertyContext (bytes: +10568, count: +264)
>    1122464      20044       56 System.ComponentModel.PropertyChangedEventHandler (bytes: -656096, count: -11716)
>     899360      16060       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +7392, count: +132)
>     899248      16058       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +7448, count: +133)


### Top of the heapshot after step 4 on iOS

> Heap shot 0 at 43.556 secs: size: 5112008, object count: 120246, class count: 372, roots: 0
>      Bytes      Count  Average Class name
>     645680      16142       40 Xamarin.Forms.BindableObject.BindablePropertyContext
>     562800      10050       56 System.ComponentModel.PropertyChangedEventHandler
>     462000       8250       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler
>     451136       8056       56 Xamarin.Forms.BindingExpression.BindingExpressionPart


### Top of the heapshot after step 5 on iOS

> Heap shot 1 at 146.149 secs: size: 9777992, object count: 230500, class count: 372, roots: 0
>      Bytes      Count  Average Class name
>    1286960      32174       40 Xamarin.Forms.BindableObject.BindablePropertyContext (bytes: +641280, count: +16032)
>    1123024      20054       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +560224, count: +10004)
>     910448      16258       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +448448, count: +8008)
>     900032      16072       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +448896, count: +8016)


## Version information

Regression status: probably not a regression. I also tested with the current stable versions, including Xamarin.Forms 1.2.3.6257.


Xamarin.Forms 1.3.0.6280-pre2


Xamarin.Android 4.20.0.28 (Business Edition)

Xamarin.iOS 8.6.0.22 (Business Edition)
Hash: 142934d
Build date: 2014-12-09 10:40:45-0500


Mono 3.12.0 ((detached/dc0ce1d)

Xamarin Studio Version 5.7 (build 646)
Release ID: 507000646
Git revision: 4574f534cc8c822ac1a4b2f31450250afb6511d3
Build date: 2014-12-09 16:28:52-05
Xamarin addins: c3c87b666323c163f0ad02618d1753533cf0a4f9


Xcode 6.1 (6604), Build 6A1052d

Mac OS X 10.9.5
Comment 2 Jason Smith [MSFT] 2014-12-30 23:53:35 UTC
Fixed in 1.3.2
Comment 3 Brendan Zagaeski (Xamarin Team, assistant) 2015-01-07 11:34:28 UTC
Bug 23807 sounds similar too. It's possible that bug has also been resolved by the fix for this bug.
Comment 4 Brendan Zagaeski (Xamarin Team, assistant) 2015-02-09 22:31:27 UTC
I got a chance today to take a quick look at the performance of this bug on 1.3.2 and above. The increases in object counts in 1.3.2 and above are about 10x better than in 1.3.0.6280-pre2 (comment 0). Perhaps these are the smallest increases possible given the current caching strategy?


For example, on iOS simulator `PropertyChangedEventHandler` increases by about 1612 instances per button tap vs. about 10004 in 1.3.0.6280-pre2.


### Results for 1.3.3.6323 after the first 3 button taps on iOS simulator

(I also tested on 1.3.4.6325-pre1 and 1.3.2.6316 with the same results.)

> $ mprof-report profiler-output.mlpd | grep -e 'Heap shot \d\|NotifyCollectionChangedEventHandler\|BindingExpressionPart\|PropertyChangedEventHandler' | grep -v 'BindingExpressionPart[[>]'
> Heap shot 0 at 12.889 secs: size: 9066800, object count: 217583, class count: 368, roots: 0
>     115920       2070       56 Xamarin.Forms.BindingExpression.BindingExpressionPart
>     115304       2059       56 System.ComponentModel.PropertyChangedEventHandler
>      68992       1232       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler
> Heap shot 1 at 23.116 secs: size: 9497016, object count: 229105, class count: 368, roots: 0
>     207088       3698       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +91168, count: +1628)
>     205576       3671       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +90272, count: +1612)
>     114016       2036       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +45024, count: +804)
> Heap shot 2 at 279.189 secs: size: 9927480, object count: 240647, class count: 368, roots: 0
>     298256       5326       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +91168, count: +1628)
>     295848       5283       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +90272, count: +1612)
>     159040       2840       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +45024, count: +804)




Unfortunately it looks like these increases in object counts do not plateau, even after many button taps. So for example, if I increase the number of iterations in the loop from 400 to 4000, I end up with many more un-collectable objects per tap.


### Results for 1.3.3.6323 after the first 4 button taps, 4000 iterations per tap

(I also tested on 1.3.4.6325-pre1 with very similar results.)

> Heap shot 0 at 141.418 secs: size: 14737984, object count: 394219, class count: 368, roots: 0
>    1123920      20070       56 Xamarin.Forms.BindingExpression.BindingExpressionPart
>    1123304      20059       56 System.ComponentModel.PropertyChangedEventHandler
>     826392      14757       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler
> Heap shot 1 at 226.591 secs: size: 18947704, object count: 508763, class count: 368, roots: 0
>    2021488      36098       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +897568, count: +16028)
>    2019976      36071       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +896672, count: +16012)
>    1274616      22761       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +448224, count: +8004)
> Heap shot 2 at 409.621 secs: size: 25126536, object count: 661907, class count: 368, roots: 0
>    3564232      63647       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +1544256, count: +27576)
>    3261552      58242       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +1240064, count: +22144)
>    2213848      39533       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +939232, count: +16772)
> Heap shot 3 at 635.522 secs: size: 30453272, object count: 808103, class count: 368, roots: 0
>    4894848      87408       56 System.ComponentModel.PropertyChangedEventHandler (bytes: +1330616, count: +23761)
>    4277056      76376       56 Xamarin.Forms.BindingExpression.BindingExpressionPart (bytes: +1015504, count: +18134)
>    2823520      50420       56 System.Collections.Specialized.NotifyCollectionChangedEventHandler (bytes: +609672, count: +10887)


## Other version info

Xamarin.iOS 8.6.1.20 (Business Edition)
Hash: 3b3ef43
Build date: 2015-01-24 09:42:21-0500

Mono 3.12.0 ((detached/de2f33f)
Xamarin Studio  5.7.1 (build 17)
Git revision: 0bc7d3550b6b088ac25b08dcf7bbe73bcc8658b3

Xcode 6.1 (6604), Build 6A1052d
Mac OS X 10.9.5
Comment 6 hassan tariq 2016-01-04 19:28:37 UTC
something..
Comment 7 Jason Smith [MSFT] 2016-03-25 18:58:21 UTC
Thank you for taking the time to submit this report. After reviewing the description of this bug, we no longer believe it affects the current version of Xamarin.Forms. If you are still experiencing the issue after updating your packages, please reopen this report with an attached reproduction.
 
For your convenience, we have created some reproduction best practices viewable here: https://gist.github.com/jassmith/92405c300e54a01dcc6d

Warm regards,
Xamarin Forms Team