Bug 12418 - Stability problem with ViewPager
Summary: Stability problem with ViewPager
Alias: None
Product: Android
Classification: Xamarin
Component: General ()
Version: 4.6.x
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Jonathan Pryor
Depends on:
Reported: 2013-05-28 05:21 UTC by Christian Papaux
Modified: 2013-07-30 02:50 UTC (History)
1 user (show)

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

ViewPagerIndicator demo modified (228.69 KB, application/x-zip-compressed)
2013-07-04 04:39 UTC, Christian Papaux
ViewPagerIndicator Bug Demo (476.42 KB, application/x-zip-compressed)
2013-07-17 01:47 UTC, Christian Papaux

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:

Description Christian Papaux 2013-05-28 05:21:54 UTC

I have some stability problems with the ViewPager depending on what is in the layout of the fragments.
The application crash (not always at the same place in the code) after several fragment changes in the ViewPager.
To reproduce this problem, you will find a modified version of the ViewPagerIndicator demo.
Run the application, select 'Tabs' and 'Default'. You will see an 'Auto' button. This button navigate 50 times between the fragments of the ViewPager.
Normally, one - two click are sufficient to crash the application.
In the layout displayed for all fragments, there are 4 TextView and 4 EditText. The 4 EditText have the property editable set to true.
If you set this property to false for all EditText, the application will not crash anymore.

Can you please check this ?

Best regards
Comment 1 Jonathan Pryor 2013-05-28 10:03:50 UTC
> To reproduce this problem, you will find a modified version of the
>  ViewPagerIndicator demo.

Where will I find this "modified version of the ViewPagerIndicator demo"?

What is the full stack trace from logcat for the crash?
Comment 4 Christian Papaux 2013-07-04 04:39:15 UTC
Created attachment 4270 [details]
ViewPagerIndicator demo modified

Here is a modified version of the ViewPagerIndicator demo to reproduce the bug.
Comment 5 Christian Papaux 2013-07-12 01:46:43 UTC

Have you been able to reproduce this bug?

Best regards
Comment 6 Jonathan Pryor 2013-07-16 15:32:25 UTC
> Have you been able to reproduce this bug?

No. I'm not able to build Attachment #4270 [details]:

> error : Cannot copy .../ViewPagerIndicator/Resources/layout/frgTestLayout.axml to .../ViewPagerIndicator/obj/Debug/res/layout/frgtestlayout.xml, as the source file doesn't exist.
+ 60 others.

Looks like in trying to shrink the .zip size you removed the Resources and Properties directories. So I copy them from the original ViewPagerIndicator sample, and I get another 23 errors:

> error CS2001: Source file `Circles/SampleCirclesDefault.cs' could not be found
+ 22 others

Simply getting this building does not fall into the "trivial" camp. :-/

Copy over more files, and:

> TestFragment.cs(48,48): error CS0117: `ViewPagerIndicator.Resource.Layout' does not contain a definition for `frgTestLayout'
> TestFragment.cs(77,65): error CS0117: `ViewPagerIndicator.Resource.Id' does not contain a definition for `lv1'

I can't fix that; I don't have frgTestLayout, I don't know what lv1 is supposed to be, I give up.

Please attach a complete sample to reproduce this bug.

Note: you don't need to provide the `bin` and `obj` directories, which will help keep the .zip size reasonable.
Comment 7 Christian Papaux 2013-07-17 01:47:19 UTC
Created attachment 4355 [details]
ViewPagerIndicator Bug Demo
Comment 8 Christian Papaux 2013-07-17 01:48:14 UTC

Sorry for the bad demo project.
I attached a new one.

Best regards
Comment 9 Jonathan Pryor 2013-07-17 10:12:34 UTC
Are you running this on hardware or the emulator?

I enabled GREF logging:


    adb shell setprop debug.mono.log gref

After tapping the Auto button once, the GREF count was at 1577. The emulator limit is 2000 GREFs.

After three taps the GREF count was 2217, which would have caused an abort when running on the emulator.

The question thus becomes, why is the GREF count so high?


# your pid/etc. will vary...
$ grep ' 2670): handle' tmp/o.txt | awk '{ print $9; }' | sort | uniq -c
   2 `android/app/ApplicationPackageManager`;
   6 `android/content/Intent`;
  34 `android/content/pm/ActivityInfo`;
  34 `android/content/pm/ApplicationInfo`;
  34 `android/content/pm/ResolveInfo`;
   7 `android/content/res/XmlBlock$Parser`;
   1 `android/support/v4/app/FragmentManagerImpl`;
   2 `android/support/v4/view/ViewPager`;
   1 `android/view/ViewGroup$LayoutParams`;
   2 `android/widget/ArrayAdapter`;
   1 `android/widget/Button`;
1080 `android/widget/EditText`;
   6 `android/widget/LinearLayout$LayoutParams`;
 271 `android/widget/LinearLayout`;
   2 `android/widget/ListView`;
1088 `android/widget/TextView`;
   1 `com/android/internal/policy/impl/PhoneLayoutInflater`;
   1 `java/lang/Class`;
  40 `java/lang/String`;
   2 `java/util/ArrayList$ArrayListIterator`;
   4 `java/util/ArrayList`;
   7 `mono/android/view/View_OnClickListenerImplementor`;
   2 `mono/android/widget/AdapterView_OnItemClickListenerImplementor`;
 301 `mono/java/lang/RunnableImplementor`;
  19 `viewpagerindicator/ActivityListItem`;
   1 `viewpagerindicator/SampleTabsDefault_GoogleMusicAdapter`;
   1 `viewpagerindicator/SampleTabsDefault`;
   6 `viewpagerindicator/TabPageIndicator_TabView`;
   1 `viewpagerindicator/TabPageIndicator`;
   6 `viewpagerindicator/TestFragment`;
   2 `viewpagerindicator/ViewPagerIndicator`;

Right away we see that EditText and TextView are consuming lots of GREFs. Search the log for TextView:

> I/monodroid-gref( 2670): handle 0x1d202a2e; key_handle 0x42e72968: Java Type: `android/widget/TextView`; MCW type: `Android.Widget.TextView`
> I/monodroid-gref( 2670): +g+ grefc 2444 gwrefc 0 obj-handle 0xb900002d/L -> new-handle 0x1d202a32/G from    at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)
> I/monodroid-gref( 2670):    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
> I/monodroid-gref( 2670):    at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
> I/monodroid-gref( 2670):    at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
> I/monodroid-gref( 2670):    at Android.Views.View..ctor(IntPtr javaReference, JniHandleOwnership transfer)
> I/monodroid-gref( 2670):    at Android.Widget.TextView..ctor(IntPtr javaReference, JniHandleOwnership transfer)
> I/monodroid-gref( 2670):    at System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod , System.Object , System.Object[] , System.Exception ByRef
>  )
> I/monodroid-gref( 2670):    at System.Reflection.MonoCMethod.InternalInvoke(System.Object obj, System.Object[] parameters)
> I/monodroid-gref( 2670):    at System.Reflection.MonoCMethod.DoInvoke(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] p
> arameters, System.Globalization.CultureInfo culture)
> I/monodroid-gref( 2670):    at System.Reflection.MonoCM

That's not particularly helpful. Search the text:

> $ grep -r TextView --include=\*.cs .
> ./Library/TabPageIndicator.cs:				TextView textView = FindViewById<TextView> (Android.Resource.Id.Text1);
> ./TestFragment.cs:      //TextView text = new TextView (Activity);
> ./TestFragment.cs:        TextView lv1 = oView.FindViewById<TextView>(Resource.Id.lv1);
> ./TestFragment.cs:        TextView lv2 = oView.FindViewById<TextView>(Resource.Id.lv2);
> ./TestFragment.cs:        TextView lv3 = oView.FindViewById<TextView>(Resource.Id.lv3);
> ./TestFragment.cs:        TextView lv4 = oView.FindViewById<TextView>(Resource.Id.lv4);

That would do it. Furthermore, those aren't used anywhere.

If I comment out the body of TestFragment.CtrlsGetRef() and re-run, then when I first tap Auto there are 325 GREFs, compared to the original 1577.

Assuming that's not ideal -- e.g. you were actually using those fields -- then the thing to realize is that the "root" of all those GREFs is the TestFragment instance itself. However, as per the above instance count, there's only 6 TestFragment instances being created.

What's happening is that those GREFs are allocated within TestFragment.OnCreateView(), which happens a lot (comparatively speaking) -- ~135 times (give or take) per tapping of Auto.

Assuming that you need `lv1`/etc., there are two solutions:

1. Call GC.Collect(). This will cause the GC to look for unused instances. In this case, if I add a GC.Collect() within TestFragment.CtrlsGetRef(), the GREF count after one click is 1992.

That's not much improvement. :-/

Explicitly calling GC.Collect() can also have noticeable slowdowns.

2. The better solution is to reduce the GREF count through `using` and/or `Dispose()` calls:

    using (TextView lv1 = oView.FindViewById<TextView>(Resource.Id.lv1))

This results in a GREF count of 325 after tapping Auto once.

In the event that `lv1` needs to be a field, you would need to override Fragment.OnDestroyView(), and `lv1.Dispose()` within OnDestroyView().
Comment 10 Christian Papaux 2013-07-30 02:50:21 UTC

Thanks for your answer, I tryed the solution overriding the OnDestroyView of the Fragment and disposing of the controls.

It's working. We will use this solution in our application.

Best regards