Bug 19316 - ListView leaks when filled in a System.Threading.Thread
Summary: ListView leaks when filled in a System.Threading.Thread
Status: RESOLVED NORESPONSE
Alias: None
Product: Android
Classification: Xamarin
Component: BCL Class Libraries ()
Version: 4.13.x
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2014-04-26 12:45 UTC by Dimitar Dobrev
Modified: 2017-06-27 00:17 UTC (History)
3 users (show)

Tags: bb
Is this bug a regression?: ---
Last known good build:

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 NORESPONSE

Description Dimitar Dobrev 2014-04-26 12:45:00 UTC
Steps to reproduce:
1. Create an activity with a list view and a button;
2. Add a handler calling GC.Collect() when the button is clicked;
3. Fill the list with non-primitive (that is, use a class, not string, int, etc.) data the following way:
   - start a new System.Threading.Thread;
   - in the passed in delegate, fill some list with data;
   - call RunOnUiThread to create an adapter (ArrayAdapter<> is fine) and set it to the list view.
4. Run an Intel emulator with GPU and Android 4.1.2;
5. Enable GREF logging;
6. Debug the application;
7. Click the GC button 2 or three times.

Expected results:
Almost all of the GREF-s are collected.

Actual results:
No more than a third of the GREF-s are collected.

Note: in the real application I get the data from a network but I think the source has nothing to do with the bug. I don't have the time to prepare a sample right now. I'm going to try to find a workaround (for example, the Android API-s for asynchronous loading) and if I fail to do so, I'll add an example.
Comment 1 Dimitar Dobrev 2014-04-26 13:40:23 UTC
The same code works fine with Java.Lang.Thread instead.
Comment 2 Jonathan Pryor 2014-05-09 16:39:47 UTC
A test case would always be helpful. That said...

Please avoid using ArrayAdapter<T>:

http://androidapi.xamarin.com/?link=T%3aAndroid.Widget.ArrayAdapter

> In Xamarin.Android, inheriting from Android.Widget.BaseAdapter is
> preferred over using ArrayAdapter unless the adapter will be storing
> Java.Lang.Object instances. The reason for this is GREF counts: many
> Android targets can only maintain a limited number of GREFs, and 
> Jwith ArrayAdapter there will be one GREF per ArrayAdapter item.
> By using BaseAdapter, this can be reduced to one GREF per displayed
> item, which for large lists can be significantly smaller.

See also: http://lists.ximian.com/pipermail/monodroid/2012-August/011730.html

> Expected results:
> Almost all of the GREF-s are collected.

Given the above explanation regarding ArrayAdapter<T> -- i.e. that an implicit GREF is taken out for EACH element that you store in the ArrayAdapter<T> instance -- why would you expect ANY GREFs to be collected? If the ArrayAdapter instance is referencing the instance, the GREF can't go away.

If you're replacing the contents of the ArrayAdapter "en mass" (or replacing the ArrayAdapter itself), you're still requiring a GREF per element, and you haven't said how large your ArrayAdapter is, as a percentage of total GREFs...

Related: `adb logcat` output containing GREF logging information would be useful.
Comment 3 Dimitar Dobrev 2014-05-13 05:21:39 UTC
The real adapter I use derives directly from BaseAdapter. I pointed ArrayAdapter out just for the sake of simplicity.
Comment 4 Jonathan Pryor 2014-05-13 11:59:45 UTC
Then a repro of some form OR a complete GREF log would is needed:

    adb shell setprop debug.mono.log gref

Note that to reasonably obtain the GREF log, you should start logging before you start the app:

    adb logcat > log.txt
    # start your app

Once your app is finished running, you can Ctrl+C the `adb logcat` command.
Comment 5 Chris Hardy [MSFT] 2017-06-26 18:06:01 UTC
Because we have not received a reply to our request for more information we are closing this issue. If you are still encountering this issue, please reopen the ticket with the requested information. Thanks!