Bug 6475 - GC runs constantly on API <= 7 targets
Summary: GC runs constantly on API <= 7 targets
Status: RESOLVED FIXED
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 4.2.x
Hardware: PC Mac OS
: --- critical
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-08-08 15:59 UTC by Jonathan Pryor
Modified: 2012-08-08 17:03 UTC (History)
1 user (show)

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


Attachments
Scratch.MaxGrefCount (13.05 KB, application/zip)
2012-08-08 15:59 UTC, Jonathan Pryor
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 Jonathan Pryor 2012-08-08 15:59:52 UTC
Created attachment 2330 [details]
Scratch.MaxGrefCount

Email thread: http://mono-for-android.1047100.n5.nabble.com/How-to-handle-garbage-collection-memory-leak-tt5711079.html#a5711096

Background: By design, each Java.Lang.Object (subclass) instance allocates a gref, available through the Object.Handle property. Also by design (starting in 4.1.x?), at startup Mono for Android computes a "maximum safe gref" count of 90% of the known platform max (i.e. 90% of 2000 for emulator, 90% of 52000 for hardware). If while running the app hits the "maximum safe gref" count, GC.Collect() is automatically invoked and a warning is issued:

> I/monodroid-gc(  356): 1800 outstanding GREFs. Performing a full GC!

The problem: There are two GC systems: one for API <= 7 (which uses java.lang.ref.WeakReference), and one for API >= 8 (which uses JNI weak references). The API7 system has a gref counting bug wherein the gref count is never reduced.

Result: once the "maximum safe gref" count is hit, we _constantly_ run GC.Collect(). Performance goes _way_ south.

This is most easily seen on the emulator (lower gref limit), but hardware could plausibly hit this as well.

To Reproduce:
1. Install the attached project on a device
2. launch it
3. click the button.
4. Read logcat output. When a GC is performed, the gref count should _fall_, as opposed to constantly increasing:

> # First time we see this, it's good; notice the 
> # dalvikvm messages stating that the gref count is decreasing...
> I/monodroid-gc(  356): 1800 outstanding GREFs. Performing a full GC!
> D/dalvikvm(  356): GC freed 2641 objects / 94176 bytes in 51ms
> D/dalvikvm(  356): GREF has decreased to 1799
> D/dalvikvm(  356): GREF has decreased to 1699
> D/dalvikvm(  356): GREF has decreased to 1599
> D/dalvikvm(  356): GREF has decreased to 1499
> D/dalvikvm(  356): GREF has decreased to 1399
> D/dalvikvm(  356): GREF has decreased to 1299
> D/dalvikvm(  356): GREF has decreased to 1199
> D/dalvikvm(  356): GREF has decreased to 1099
> D/dalvikvm(  356): GREF has decreased to 999
> D/dalvikvm(  356): GREF has decreased to 899
> D/dalvikvm(  356): GREF has decreased to 799
> D/dalvikvm(  356): GREF has decreased to 699
> D/dalvikvm(  356): GREF has decreased to 599
> D/dalvikvm(  356): GREF has decreased to 499
> D/dalvikvm(  356): GREF has decreased to 399
> D/dalvikvm(  356): GREF has decreased to 299
> D/dalvikvm(  356): GREF has decreased to 199
>
> # Here things go way off the rails. We just decreased the gref count, but monodroid doesn't know it...
> I/monodroid-gc(  356): 1800 outstanding GREFs. Performing a full GC!
> D/dalvikvm(  356): GC freed 1990 objects / 65896 bytes in 45ms
> I/monodroid-gc(  356): 1801 outstanding GREFs. Performing a full GC!
> D/dalvikvm(  356): GC freed 4 objects / 96 bytes in 38ms
> I/monodroid-gc(  356): 1801 outstanding GREFs. Performing a full GC!
> D/dalvikvm(  356): GC freed 4 objects / 120 bytes in 38ms
...
> I/monodroid-gc(  356): 7693 outstanding GREFs. Performing a full GC!
Comment 1 Jonathan Pryor 2012-08-08 17:03:51 UTC
Fixed in master/5340dfa5.