使用Google Maps API时出现内存不足错误

7
我这里有一个应用程序,它具有在地图上显示POI的功能。只有一个POI,当它实际在可见屏幕区域内时才会绘制。它可以正常工作一段时间,但如果我玩耍缩放和拖动,它最终会崩溃。根据Logcat,原因总是OutOfMemory错误。
起初,我以为这是Google Maps API的一个bug。经过一些研究并看到一些Romain Guy的帖子后,我有点相信我在我的应用程序中做了一些愚蠢的事情,使我不时地耗尽内存。 然后我进行了更详细的Heap Analyzer(Eclipse)测试,并发现即使我还剩下2+、有时甚至3+兆字节的空闲内存,我仍然会收到那些讨厌的强制关闭消息,导致OutOfMemoryError。大多数情况下,它在尝试分配一些614kb的内存块时崩溃,而不管我还剩多少内存。
这个问题在Nexus One 2.2.1和HTC Evo 2.1上经常发生。经过一些简单的测试,我在G1 1.6和三星Galaxy S i9000 2.1上没有崩溃。但我不能确定在更多测试后G1和Galaxy是否会出现这个问题。
我只能想到一个内存碎片化的问题。我希望这个问题有解决办法。如果可以,我也很高兴能够捕获这个错误并防止应用程序崩溃。
如果有帮助的话,这里是logcat:
09-29 08:58:06.661: ERROR/dalvikvm-heap(1552): 648000-byte external allocation too large for this process.
09-29 08:58:06.661: ERROR/dalvikvm(1552): Out of memory: Heap Size=9991KB, Allocated=6980KB, Bitmap Size=14510KB
09-29 08:58:06.661: ERROR/(1552): VM won't let us allocate 648000 bytes
09-29 08:58:06.672: DEBUG/AndroidRuntime(1552): Shutting down VM
09-29 08:58:06.672: WARN/dalvikvm(1552): threadid=3: thread exiting with uncaught exception (group=0x4001b390)
09-29 08:58:06.672: ERROR/AndroidRuntime(1552): Uncaught handler: thread main exiting due to uncaught exception
09-29 08:58:06.681: ERROR/AndroidRuntime(1552): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.graphics.Bitmap.nativeCreate(Native Method)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.graphics.Bitmap.createBitmap(Bitmap.java:569)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:422)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.google.android.maps.ZoomHelper.beginZoom(ZoomHelper.java:186)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.google.android.maps.MapView$2.onScaleBegin(MapView.java:371)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:208)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.google.android.maps.MapView.onTouchEvent(MapView.java:646)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.View.dispatchTouchEvent(View.java:3709)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:874)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:924)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:924)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:924)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1701)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1116)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.app.Activity.dispatchTouchEvent(Activity.java:2068)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1685)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1708)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.os.Looper.loop(Looper.java:123)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at android.app.ActivityThread.main(ActivityThread.java:4595)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at java.lang.reflect.Method.invokeNative(Native Method)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at java.lang.reflect.Method.invoke(Method.java:521)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
09-29 08:58:06.681: ERROR/AndroidRuntime(1552):     at dalvik.system.NativeStart.main(Native Method)

我从使用OS版本1.5、2.1和2.2的用户那里收到了相同的错误报告。堆栈跟踪没有经过我的代码,因此我无法捕获此错误 - 应用程序以FC结束。 - tomash
真的看起来像是一种分段问题。就好像我的应用程序有一些内存泄漏,会将微小的数据块分散在我的堆内存区域中。我猜这种行为可能会在 Dalvik 的下一个版本中得到改进,因为它可能不是一个 bug,但肯定不是一个“好的行为”,因为你实际上拥有内存,但由于其分段,系统无法使用。好吧,我会继续努力看看能做些什么。 - Rafael Ramos
我知道这个问题已经超过一年了,但是针对这个问题是否已经开发出解决方案了呢?我很好奇。提前感谢! - Ahmed Faisal
3个回答

1

我一直遇到这个完全相同的问题,我在代码中加入了一些System.GC调用,似乎有所帮助,但仍然会出现这种情况。

我还遇到另一个问题,可能与此相关,当你捏缩放时,地图似乎会翻转并随机显示。有时在崩溃之前会发生这种情况。

这只发生在HTC Desire上,我认为它与Nexus One在内部是相同的手机。(并且与EVO在许多方面也相似,也受到了影响)。

注意:我们的Arc-S、Galaxy V1、AVD模拟器和Asus平板电脑上都可以正常工作。


1

我曾经遇到过同样的问题,在应用程序标签下的清单文件中添加以下行:

android:largeHeap = true。这对我有用。


它可以提高崩溃率,但并不能完全解决问题。 - Kaveesh Kanwal
这基本上是一个备用方案,只有在绝对无法正常工作的情况下才会使用。 - Kaveesh Kanwal

1
我在过去的一个月中一直遇到这个问题。我在代码中解决问题的方式是强制GC清理我已经用WeakReferences包装的未引用的位图。由于你贴出的崩溃似乎源自MapView,这种方法可能不适用于您。无论如何,在您的代码的关键位置添加一些System.gc()调用,并监视系统日志,以查看GC_EXPLICIT消息是否指示释放了大量对象/字节。在我正在处理的代码中,我不得不在Adapter.getView()方法的末尾添加一个System.gc()来确保下一次调用getView()时清理未使用的位图。这种方法似乎已经极大地减少了我与可怕的java.lang.OutOfMemoryError: bitmap size exceeds VM budget崩溃的冲突。

调用System.gc()不应该帮助OOME。在尝试运行GC本身之前,VM不会抛出OOME。此外,System.gc()对于碎片化无济于事。 - Jeffrey Blattman
这些OOME错误往往更频繁地发生在Galaxy系列手机上,如Nexus One和Nexus S。我没有使用Galaxy Nexus太多来检查与其他手机相比是否也更容易出现此问题。通过调用GC清理内存以及谨慎编码是避免此问题的最佳方法,据我所知。人们还可以捕获异常(作为Throwable),至少可以防止应用程序强制关闭。但不幸的是,我不确定是否有一个明确的解决方案来解决这个问题... - Rafael Ramos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接