当前位置: 首页 > 面试题库 >

Android-仅在具有MapView的单个Activity上有许多OutOfMemoryError异常

强硕
2023-03-14
问题内容

我的用户收到了很多OutOfMemoryError报告,每个报告都来自同一个Activity,其中包含MapView。我认为这是一个孤立的异常,仅在我的应用程序中只有一个位置,而且我无法弄清楚问题出在哪里。谁能给我一些指示为什么会这样吗?

我已针对此问题删除了一些不需要的代码,因此如果有人认为问题可能在于此,我将其发布。

堆栈痕迹

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)

活动

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;
}
}

十字线叠加

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

问题答案:

我下载了该应用程序并在通过dumpsys观察内存的同时进行了操作。

情况看起来很正常,每次都会回收内存。我无法重现这种情况,但是我确实看到一个可能与之相关的峰值。每当您在地图上四处移动或在卫星中缩放(基本刷新图块)时,内存中都会出现短暂的峰值。如果您执行得足够快,则不会给它回收的机会,它会上升。

现在,我的手机是Android
3.3.4,并且配置良好,因此GC可能效率更高。我不知道我的旧测试电话是否会较慢地回收内存,因此,当我到达地图时(例如,添加鱼后),我是否仍会保留以前未被GC回收的活动中的内存。然后,我要做的就是去我的位置并通过放大/缩小来检查内容。加上以前的活动中的先前记忆,可能会使手机达到极限。

不过,这只是一个理论,我在旅途中,无法使用我所有的测试电话。您知道崩溃的手机版本吗?我会在3-4天后回来,我可以在旧手机上尝试该应用。

更新: 我已经在这个应用程序上进行了更多的实验。我几乎可以肯定,连续添加鱼会增加更多的回忆。我一直在添加和删除鱼,并通过dumpsys
meminfo检查内存是否持续增加。专业版的真正用户,甚至是不断添加和删除鱼的精简版用户,最终可能会接近极限并随后进入地图,这将触发内存不足错误,因为内存会进入地图。这是我几次添加和删除鱼后的快照

** pid 11572中的MEMINFO [com.hookedroid.fishingcompanion.lite] **
                    dalvik本机其他总数限制位图nativeBmp
            大小:19728 18251不适用37979 32768不适用
       已分配:17174 14674 N / A 31848 N / A 3144 0
            免费:405 3577 N / A 3982 N / AN / AN / A
           (PSS):12750 1771 25944 40465 N / AN / AN / A
  (脏共享):908 1544 5800 8252 N / AN / AN / A
    (私人肮脏):12732 1008 24208 37948 N / AN / AN / A

您的私有内存总数达到37,948,如果我继续添加和删除鱼,我敢肯定,它将最终抛出OutOfMemoryException

更多更新(几分钟后): 我使用上述理论使应用程序崩溃。在发生之前,我必须多次添加和移除鱼。该应用程序崩溃之前可能超过50条鱼。

我的猜测是SQL无法正确清理。在每组添加和删除10条鱼(这是lite版本的限制)之后查看一下dumpsys,我看到

的SQL
               堆:6581 MEMORY_USED:6581
 PAGECACHE_OVERFLOW:173 MALLOC_SIZE:50

 资料库
      pgsz dbsz Lookaside(b)Dbname
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 33钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣
         1 16 62钓鱼伴侣

即使我已经删除了鱼,SQL内存仍在增加。如果我继续这样做一段时间,最终它将达到手机的上限,并且转到地图(这会导致内存中的跳转)将触发内存不足异常,似乎表明地图页面是原因,而我认为添加/删除鱼页面是真正原因的一部分(我说“真正原因的一部分”,因为我不知道是否会发生类似的影响,例如我是否添加新位置)。

当总内存约为58MB时,我得到了正确的OutMemoryException(这可能因手机而异)。作为参考,这是我得到的一个类似的OutOfMemoryException:

D / dalvikvm(11572):GC_FOR_MALLOC释放了125K,11%释放了25734K / 28743K,外部4047K / 4695K,暂停了188ms
D / AndroidRuntime(11572):关闭VM
W / dalvikvm(11572):threadid = 1:线程以未捕获的异常退出(group = 0x4001d648)
E / AndroidRuntime(11572):致命异常:主要
E / AndroidRuntime(11572):java.lang.OutOfMemoryError:位图大小超出VM预算(堆大小= 28743KB,已分配= 25734KB,位图大小= 4047KB)
E / AndroidRuntime(11572):位于android.graphics.Bitmap.nativeCreate(本机方法)
E / AndroidRuntime(11572):位于android.graphics.Bitmap.createBitmap(Bitmap.java:695)
E / AndroidRuntime(11572):位于com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444)
E / AndroidRuntime(11572):位于com.google.android.maps.ZoomHelper.beginZoom(ZoomHelper.java:194)
E / AndroidRuntime(11572):位于com.google.android.maps.MapView $ 2.onScaleBegin(MapView.java:380)
E / AndroidRuntime(11572):位于android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:216)
E / AndroidRuntime(11572):位于com.google.android.maps.MapView.onTouchEvent(MapView.java:682)
E / AndroidRuntime(11572):位于android.view.View.dispatchTouchEvent(View.java:3932)
E / AndroidRuntime(11572):位于android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:955)
E / AndroidRuntime(11572):位于android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
E / AndroidRuntime(11572):位于android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
E / AndroidRuntime(11572):位于android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)

希望能帮助到你



 类似资料:
  • 编辑: 我正在使用热切加载,我认为这将影响它的工作方式。

  • 我有一个类处理一个图像,这可能是一个缓慢的过程。当工作完成时,该类包含图像的一些特性,如主色。 我有许多其他的代码想知道主颜色,当他们要求它时,它可能是或可能没有准备好。 我还没有找到使用RXJava2实现这一点的简单方法。有人能帮帮我吗? null ReplaySubject似乎有一些我正在寻找的属性,但我不确定如何正确地实现它。

  • 例如: 如果父div具有类为“not_available”的内部div,则需要隐藏“快速订购”按钮 尝试了一些JavaScript: 另一个JavaScript示例: 但是它或者根本不起作用,或者对所有具有class.quckorder-btn的div都起作用。只需要在一个div中运行函数,该div中没有一个div具有类“not_available” 请求任何帮助。谢谢

  • 我正在尝试从技能作业表中删除一行 以下是我的疑问 但它抛出以下错误; 致命错误:未捕获的异常'异常'消息'您有一个错误在您的SQL语法;检查手册,对应于您的MySQL服务器版本的正确的语法使用附近'skj内连接作业j上<--plhd--0/<--#############################################################################

  • Camel in Action的结尾是在时使用

  • 问题内容: 我正在编写此android应用程序,其中有许多扩展Activity类的活动。我还需要一个使用MapView在屏幕上同时显示Map和ListView的活动(类似于在地图上使用图钉显示房屋的出租房屋清单)。由于我有一个扩展Activity类的基类,因此其他活动扩展了该基类。只有具有地图的特定屏幕才需要扩展MapActivity类。当我尝试这样做时,我抛出了IllegalAccessErro