Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
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
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.
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.
Almost all of the GREF-s are collected.
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.
The same code works fine with Java.Lang.Thread instead.
A test case would always be helpful. That said...
Please avoid using ArrayAdapter<T>:
> 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.
The real adapter I use derives directly from BaseAdapter. I pointed ArrayAdapter out just for the sake of simplicity.
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.
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!