Android - many OutOfMemoryError exceptions for single activity only with MapView

I get quite a few OutOfMemoryError reports from my users, and each individual report belongs to the same Activity that contains the MapView. I think this is an isolated exception with only this place in my application, and I cannot figure out what the problem is. Can someone give me some guidance as to why this is happening?

I deleted the unnecessary code for this question, so if someone thinks that the problem may be this, I will send it.

Stack trace

Stack Trace #1 java.lang.OutOfMemoryError: bitmap size exceeds VM budget at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:677) at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444) at com.google.android.maps.ZoomHelper.beginZoom(ZoomHelper.java:194) at com.google.android.maps.MapView$2.onScaleBegin(MapView.java:371) at android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:216) at com.google.android.maps.MapView.onTouchEvent(MapView.java:646) at android.view.View.dispatchTouchEvent(View.java:3778) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:920) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1716) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1124) at android.app.Activity.dispatchTouchEvent(Activity.java:2125) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1700) at android.view.ViewRoot.handleMessage(ViewRoot.java:1822) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:143) at android.app.ActivityThread.main(ActivityThread.java:5068) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) at dalvik.system.NativeStart.main(Native Method) Stack Trace #2 java.lang.OutOfMemoryError: bitmap size exceeds VM budget at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:468) at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444) at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:151) at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:140) at com.google.android.maps.MapView.doZoom(MapView.java:1478) at com.google.android.maps.MapView.doZoom(MapView.java:1487) at com.google.android.maps.MapController.zoomOut(MapController.java:439) at com.hookedroid.fishingcompanion.GoogleMaps$3.onClick(GoogleMaps.java:133) at android.view.View.performClick(View.java:2405) at android.view.View$PerformClick.run(View.java:8813) at android.os.Handler.handleCallback(Handler.java:587) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4627) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) at dalvik.system.NativeStart.main(Native Method) Stack Trace #3 java.lang.OutOfMemoryError: bitmap size exceeds VM budget at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:468) at android.graphics.Bitmap.createBitmap(Bitmap.java:435) at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340) at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323) at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:346) at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:372) at com.hookedroid.fishingcompanion.maps.CrosshairOverlay.draw(CrosshairOverlay.java:32) at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:45) at com.google.android.maps.MapView.onDraw(MapView.java:494) at android.view.View.draw(View.java:6742) at android.view.ViewGroup.drawChild(ViewGroup.java:1640) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) at android.view.ViewGroup.drawChild(ViewGroup.java:1638) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) at android.view.View.draw(View.java:6745) at android.widget.FrameLayout.draw(FrameLayout.java:352) at android.view.ViewGroup.drawChild(ViewGroup.java:1640) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) at android.view.View.draw(View.java:6745) at android.widget.FrameLayout.draw(FrameLayout.java:352) at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1913) at android.view.ViewRoot.draw(ViewRoot.java:1407) at android.view.ViewRoot.performTraversals(ViewRoot.java:1163) at android.view.ViewRoot.handleMessage(ViewRoot.java:1727) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4646) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) at dalvik.system.NativeStart.main(Native Method) 

activity

 public class GoogleMaps extends MapActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.googlemaps_layout); intent = getIntent(); currentMode = intent.getIntExtra("MAP_MODE", 0); initControls(); initMembers(); currentOverlayMode = prefs.getInt("map_viewmode", 0); populateMap(); } private void initMembers() { mDbHelper = new FishingCompanionDB(this); mDbHelper.open(); catchList = new ArrayList<FishEntry>(); prefs = PreferenceManager.getDefaultSharedPreferences(this); prefsEditor = prefs.edit(); } private void initControls() { mMaps = (MapView)findViewById(R.id.google_maps); mMaps.setClickable(true); mMaps.setLongClickable(true); mapController = mMaps.getController(); mOverlayModeBtn = (Button)findViewById(R.id.googlemaps_overlay_btn); mOverlayModeBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { if (currentOverlayMode < 1) currentOverlayMode++; else currentOverlayMode = 0; switch (currentOverlayMode) { case OVERLAY_STREET: mMaps.setSatellite(false); mMaps.setStreetView(true); prefsEditor.putInt("map_viewmode", OVERLAY_STREET); break; case OVERLAY_SAT: mMaps.setStreetView(false); mMaps.setSatellite(true); prefsEditor.putInt("map_viewmode", OVERLAY_SAT); break; } prefsEditor.commit(); mMaps.invalidate(); } }); mZoomInBtn = (Button)findViewById(R.id.googlemaps_btn_zoomin); mZoomInBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { mapController.zoomIn(); } }); mZoomOutBtn = (Button)findViewById(R.id.googlemaps_btn_zoomout); mZoomOutBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { mapController.zoomOut(); } }); } private void populateMap() { overlays = mMaps.getOverlays(); overlays.clear(); overlays.add(new CrosshairOverlay(this, R.drawable.mapcenter)); mSelectPos = (Button)findViewById(R.id.googlemaps_select_location); mSelectPos.setVisibility(View.VISIBLE); mSelectPos.setOnClickListener(new OnClickListener() { public void onClick(View v) { GeoPoint centerGp = mMaps.getMapCenter(); double lat = centerGp.getLatitudeE6()/1E6; double lng = centerGp.getLongitudeE6()/1E6; Intent i; if (currentMode == SELECT_POS_WEATHER) { i = new Intent(GoogleMaps.this, WeatherLookup.class); i.putExtra("WEATHER_LAT", lat); i.putExtra("WEATHER_LNG", lng); } else { i = new Intent(GoogleMaps.this, AddLocation.class); i.putExtra("LOCATION_LAT", lat); i.putExtra("LOCATION_LNG", lng); } i.putExtra("MODE", 1); startActivity(i); finish(); } }); mMaps.invalidate(); } @Override protected boolean isRouteDisplayed() { return false; } } 

Crosshair overlay

 public class CrosshairOverlay extends Overlay { private Context mContext; private int resourceId; public CrosshairOverlay(Context context, int resId) { this.mContext = context; this.resourceId = resId; } public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { super.draw(canvas, mapView, shadow); GeoPoint centerGp = mapView.getMapCenter(); Projection projection = mapView.getProjection(); Point centerPoint = projection.toPixels(centerGp, null); Paint p = new Paint(); Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), resourceId); canvas.drawBitmap(bmp, (centerPoint.x - (bmp.getWidth()/2)), (centerPoint.y - (bmp.getHeight()/2)), p); return true; } } 

DUMPSYS MEMINFO

 ** MEMINFO in pid 25493 [com.hookedroid.fishingcompanion] ** native dalvik other total size: 10036 7495 N/A 17531 allocated: 9955 3965 N/A 13920 free: 80 3530 N/A 3610 (Pss): 3717 1480 6703 11900 (shared dirty): 668 1512 8056 10236 (priv dirty): 3696 804 5024 9524 Objects Views: 0 ViewRoots: 0 AppContexts: 0 Activities: 0 Assets: 3 AssetManagers: 3 Local Binders: 19 Proxy Binders: 21 Death Recipients: 1 OpenSSL Sockets: 0 SQL heap: 527 MEMORY_USED: 527 PAGECACHE_OVERFLOW: 62 MALLOC_SIZE: 50 DATABASES pgsz dbsz Lookaside(b) Dbname 1 16 260 FishingCompanion 1 18 63 google_analytics.db 
0
source share
2 answers

I downloaded the application and played with it, watching memory through dumpsys.

Everything looks normal, the memory is restored every time. I cannot reproduce the situation, but I see one surge that is probably related. Whenever you move around the map or scale (mainly updating tiles) on the satellite, there will be a brief burst of memory. If you do it fast enough, you will not give him the opportunity to return it, and it will grow.

Now my phone is Android 3.3.4 and has a pretty good configuration, so perhaps the GC is much more efficient. It is interesting, though, if my old test phones will recover memory more slowly, and therefore, when I get to the map (say, after adding fish), I will still have memory from a previous activity that was not restored by GC. Then what would I do, I would go to my location and check the situation by zooming in / out. This, combined with previous memory from previous actions, can cause phones to reach the limit.

This is just a theory, although I am on the road and do not have access to all my test phones. Do you know which version of failed phones? I will be back in 3-4 days, and I can try the application on my old phones.

UPDATED: I conducted more experiments on this application. I am pretty sure that adding fish continuously will add more memories. I continued to add and remove fish and verify that memory continues to grow through dumpsys meminfo. Real users of the Pro Edition or even Lite, who continue to add and remove fish, may ultimately get close to the limit, and after that the transition to the card will cause an error in the memory, as there will be a memory jump on the card. Here is a snapshot after adding and removing fish several times.

  ** MEMINFO in pid 11572 [com.hookedroid.fishingcompanion.lite] **
                     native dalvik other total limit bitmap nativeBmp
             size: 19728 18251 N / A 37979 32768 N / AN / A
        allocated: 17174 14674 N / A 31848 N / A 3144 0
             free: 405 3577 N / A 3982 N / AN / AN / A
            (Pss): 12750 1771 25944 40465 N / AN / AN / A
   (shared dirty): 908 1544 5800 8252 N / AN / AN / A
     (priv dirty): 12732 1008 24208 37948 N / AN / AN / A

Your personal memory will move to 37,948, and I'm sure that if I continue to add and remove fish, it will eventually throw an OutOfMemoryException.

MORE UPDATES (a few minutes later): I manage to collapse the application using the above theory. I had to add and remove fish several times before this happened. It can be more than 50 fish before the application crashed.

I assume that for some reason SQL is not being cleaned properly. Looking at dumpsys after each set of adding and removing 10 fish (which is the limit of the lite version), I see that

  SQL
                heap: 6581 MEMORY_USED: 6581
  PAGECACHE_OVERFLOW: 173 MALLOC_SIZE: 50

  DATABASES
       pgsz dbsz Lookaside (b) dbname
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 33 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion
          1 16 62 FishingCompanion

SQL memory continues to grow, although I have already deleted the fish. If I continue to do this for some time, in the end it will fall into the upper limit of the phone and go to the card (which will cause a jump in memory) will cause an exception in memory, which would seem to indicate that the map page is the reason, whereas I think that the add / remove fish page is part of the real reason (I say โ€œpart of the real reasonโ€ because I donโ€™t know if such an action will happen if I add a new location).

I got an OutMemoryException correctly when the total memory is about 58 MB (this is probably different from phone to phone). For reference, here is a similar OutOfMemoryException exception that I received:

  D / dalvikvm (11572): GC_FOR_MALLOC freed 125K, 11% free 25734K / 28743K, external 4047K / 4695K, paused 188ms
 D / AndroidRuntime (11572): Shutting down VM
 W / dalvikvm (11572): threadid = 1: thread exiting with uncaught exception (group = 0x4001d648)
 E / AndroidRuntime (11572): FATAL EXCEPTION: main
 E / AndroidRuntime (11572): java.lang.OutOfMemoryError: bitmap size exceeds VM budget (Heap Size = 28743KB, Allocated = 25734KB, Bitmap Size = 4047KB)
 E / AndroidRuntime (11572): at android.graphics.Bitmap.nativeCreate (Native Method)
 E / AndroidRuntime (11572): at android.graphics.Bitmap.createBitmap (Bitmap.java:695)
 E / AndroidRuntime (11572): at com.google.android.maps.ZoomHelper.createSnapshot (ZoomHelper.java:444)
 E / AndroidRuntime (11572): at com.google.android.maps.ZoomHelper.beginZoom (ZoomHelper.java:194)
 E / AndroidRuntime (11572): at com.google.android.maps.MapView $ 2.onScaleBegin (MapView.javahaps80)
 E / AndroidRuntime (11572): at android.view.ScaleGestureDetector.onTouchEvent (ScaleGestureDetector.java:216)
 E / AndroidRuntime (11572): at com.google.android.maps.MapView.onTouchEvent (MapView.java:682)
 E / AndroidRuntime (11572): at android.view.View.dispatchTouchEvent (View.java:3932)
 E / AndroidRuntime (11572): at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:955)
 E / AndroidRuntime (11572): at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1015)
 E / AndroidRuntime (11572): at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1015)
 E / AndroidRuntime (11572): at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1015)

Hope this helps

+7
source

I am not sure if this is related to your problem.

this link regards <strong memory leak problem and proposed solution. based on the fact that I use this version in my extended MyMapView and call this method in the appropriate places.

 public void cleanUpMemory(){ try { Field fMapInView = MapView.class.getDeclaredField("mMap"); AccessibleObject.setAccessible(new AccessibleObject[]{fMapInView}, true); fMapInView.set(this, null); } catch (Exception e) { e.printStackTrace(); } try { Field fConverterInView = MapView.class.getDeclaredField("mConverter"); AccessibleObject.setAccessible(new AccessibleObject[]{fConverterInView}, true); fConverterInView.set(this, null); } catch (Exception e) { e.printStackTrace(); } try { Field fControllerInView = MapView.class.getDeclaredField("mController"); AccessibleObject.setAccessible(new AccessibleObject[]{fControllerInView}, true); fControllerInView.set(this, null); } catch (Exception e) { e.printStackTrace(); } try { Field fZoomHelperInView = MapView.class.getDeclaredField("mZoomHelper"); AccessibleObject.setAccessible(new AccessibleObject[]{fZoomHelperInView}, true); fZoomHelperInView.set(this, null); } catch (Exception e) { e.printStackTrace(); } } 
+1
source

All Articles