dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.93k stars 531 forks source link

Xamarin.Android app with Google Maps crashes with out of memory #3057

Closed anurag-bharti03 closed 5 years ago

anurag-bharti03 commented 5 years ago

Steps to Reproduce

  1. Add two activities to the Xamarin.Android app with a MapFragment in the second activity
  2. Navigate back and forth between the two activities multiple times.
  3. App crashes with the following messages in the logs - 'sharedmem_gpumem_alloc: mmap failed errno 12 out of memory'

Expected Behavior

MapFragments should get disposed after a new activity is started.

Actual Behavior

Every time when the app navigates to the activity with map, the app memory usage increases to around 80-90 MB, resulting in a crash after several attempts.

Version Information

Log File

05-02 13:24:07.311 I/mobileapp.droi(29917): NativeAlloc concurrent copying GC freed 32016(1119KB) AllocSpace objects, 0(0B) LOS objects, 50% free, 16MB/33MB, paused 521us total 154.777ms 05-02 13:24:07.609 W/Adreno-GSL(29917): : sharedmem_gpumem_alloc: mmap failed errno 12 Out of memory 05-02 13:24:07.609 E/Adreno-GSL(29917): : GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.

anurag-bharti03 commented 5 years ago

Code:

 _mapFragment = FragmentManager.FindFragmentById<MapFragment>(Resource.Id.map);
 _mapFragment.GetMapAsync(mapReadyCallback);

 mapReadyCallback.MapReadyAction += delegate (GoogleMap obj)
                {
                    GMap = obj;
                    GMap.MyLocationEnabled = true;
                    GMap.MapType = GoogleMap.MapTypeNormal;
                    GMap.UiSettings.ScrollGesturesEnabled = true;
                    GMap.UiSettings.MapToolbarEnabled = false;
                    GMap.UiSettings.ZoomControlsEnabled = true;
                    GMap.MyLocationEnabled = true;
                    GMap.UiSettings.MyLocationButtonEnabled = true;
                    GMap.SetOnMapClickListener(this);
                    GMap.Clear();
                    droidLocationUtility.MarkOnMap(Resource.Drawable.TechnicianIcon);
                    GMap.MyLocationButtonClick += GMap_MyLocationButtonClick;
};

public void MarkOnMap(int resourceId)
{
   _currentLocationMarkerOptions = new MarkerOptions();
   _currentLocationMarkerOptions.SetTitle(title);
   _currentLocationMarkerOptions.SetPosition(new LatLng(AppGlobal.Latitude, AppGlobal.Longitude));                      
   _currentLocationMarkerOptions.SetIcon(BitmapDescriptorFactory.FromResource(resourceId));
   _currentLocationMarkerOptions.Draggable(false);
   _currentLocationMarker = GMap.AddMarker(_currentLocationMarkerOptions);
}
jonathanpeppers commented 5 years ago

@anuragbharti-igs can you post the full Android device log when you hit the crash?

Would you also be able to post a small project that shows this issue when using Google Maps?

anurag-bharti03 commented 5 years ago

App.log Device.log GoogleMapDemo.zip @jonathanpeppers

anurag-bharti03 commented 5 years ago

@jonathanpeppers I have uploaded a solution which demonstrates the google map implementation in my solution. I have also attached device logs and Visual studio debug logs

MihaMarkic commented 5 years ago

@anuragbharti-igs I think it might be xamarin GC unaware of java GC. Try calling GC.Collect() between navigations and see if it still crashes.

anurag-bharti03 commented 5 years ago

@MihaMarkic Thanks for the suggestion. I tried calling GC.Collect() between navigations but the app still crashes due to out of memory. It just delays the crash but doesn't solve the issue.

MihaMarkic commented 5 years ago

@anuragbharti-igs So I added this to HomeActivity

protected override async void OnResume()
        {
            base.OnResume();
            await Task.Delay(2000);
            StartActivity(typeof(MainActivity));
        }

and this to MainActivity

protected override async void OnResume()
        {
            base.OnResume();
            await Task.Delay(2000);
            Finish();
        }

I left it to run for like 10 minutes and no out of memory exception on sight. How many forth and back cycles does it take for you to crash the app? Emulator? Real device?

anurag-bharti03 commented 5 years ago

@MihaMarkic I am running it on a real device. My app has a Home Screen with few cells elements in GridView in a home screen. On click of any cell, next screen appears which has a map fragment and google places fragment and a RecyclerView at the bottom. The map fragment has 4-5 markers on it. On click of any cell in the RecyclerView, the app navigates to the next screen which also has a map fragment with a single marker an a button at the bottom. When either of the activities with map fragments are started, the memory usage jumps to 60-70 MB. If the app is run from end to end for around 20-30 times, it crashes due to low memory

jonathanpeppers commented 5 years ago

@anuragbharti-igs in addition to @MihaMarkic's suggestion of adding some GC.Collect() calls, you can add some cleanup in each activity in OnDestroy(). I would try calling Dispose() on any of the google maps objects--to see if that helps.

I looked at your project and I don't see anything out of the ordinary (it works for me as well).

It might be your device is older than mine? I have a Pixel 3 XL.

anurag-bharti03 commented 5 years ago

@jonathanpeppers I tried disposing the MapFragment in the OnDestroy() of my Activity and I am not facing any crashes as of now.