【问题标题】:Out of memory error when restarting app (Android)重新启动应用程序时出现内存不足错误(Android)
【发布时间】:2012-12-29 23:22:37
【问题描述】:

我正在开发一个使用 5 个大约 900x600 的大图像的游戏。当我退出游戏(按返回键)然后尝试启动游戏时,出现以下错误:

12-29 15:59:16.633: E/AndroidRuntime(18642): FATAL EXCEPTION: GLThread 17
12-29 15:59:16.633: E/AndroidRuntime(18642): java.lang.OutOfMemoryError: (Heap  Size=20423KB, Allocated=3473KB, Bitmap Size=77KB)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.util.GLHelper.getPixelsARGB_8888(GLHelper.java:165)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.util.GLHelper.getPixels(GLHelper.java:41)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.util.GLState.glTexImage2D(GLState.java:641)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.texture.bitmap.BitmapTexture.writeTextureToHardware(BitmapTexture.java:120)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.texture.Texture.loadToHardware(Texture.java:137)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.texture.TextureManager.updateTextures(TextureManager.java:254)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.engine.Engine.onDrawFrame(Engine.java:621)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at org.andengine.opengl.view.EngineRenderer.onDrawFrame(EngineRenderer.java:105)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1363)
12-29 15:59:16.633: E/AndroidRuntime(18642):    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1118)

这真的很令人困惑,因为我在应用程序被销毁之前卸载了所有纹理。我知道这 5 张图片导致了错误,因为当我完全跳过加载它们时,我没有收到任何错误。为了确保所有纹理都被卸载,我加载了纹理并在卸载它们之后立即加载。然后我退出并重新启动游戏,但收到同样的错误。纹理也没有任何静态引用。我还使用 MAT 查看我在游戏中使用了多少内存,并注意到我只使用了 2.5MB,所以我不知道为什么错误是“堆大小 = 20MB”。我暂时设法解决错误的唯一方法是包含

system.exit(0);

我知道我不应该使用它,但我完全没有想法。

编辑:我确保正在卸载纹理。我在游戏中有一个按钮可以卸载所有纹理。当我按下它时,所有纹理都变黑了,我假设已卸载纹理。我在卸载纹理时使用的一般方法只是说

someTexture.unload();

这是一个andEngine方法。我不确定除此之外会发生什么。

编辑 2:我在名为 onCreateResources() 的方法中加载纹理,然后在 onDestroy() 中卸载它们。这些是我操纵纹理的唯一两个地方。

【问题讨论】:

  • 你确定纹理已经发布了吗?你是如何卸载他们的?
  • 您正在使用不同的线程来处理图像,您是否在创建新线程之前明确销毁了旧线程?
  • 你在使用 Bitmap.recycle() 吗? :) 另外,尝试通过连续调用几次来强制 GC 或通过使用 cmdline 参数 -Xmx 来增加堆大小
  • 您是否在 onPause() 中卸载它们并在 onResume() 方法中重新加载它们?单独的堆栈跟踪在这里没有帮助......所以,向我们展示。
  • 我更新了帖子以展示我如何删除纹理。我只卸载 onDestroy() 上的纹理。

标签: android memory-leaks andengine


【解决方案1】:

如果我从 Android API 中没记错的话: 按下后退按钮并不一定意味着 onDestroy()。 Android 操作系统会为您处理垃圾收集并在需要时调用 onDestroy()(例如,当您按下返回按钮后启动了更多应用时)。

但是,有些 ROM 允许您通过长按返回按钮“杀死”应用程序。

您可以尝试从 onStop() 中卸载纹理并报告回来吗?

编辑:没有看到 Shark 的回复。 OnPause() 也可以工作——同样的概念……事实上 onPause() 总是在 OnStop() 之前调用,所以它可能是一个更好的解决方案。

【讨论】:

  • 我刚刚做了,但仍然遇到同样的错误。我还检查了:当我按下(通过 logcat)时,确实调用了 onDestroy()。不过感谢您的建议。
【解决方案2】:

垃圾收集器不会立即释放未使用的对象内存,因此如果您尝试在短时间内重新加载新位图,则没有可用内存可供使用。

也许您应该使用 Wea​​kReference:JVM 必须在抛出 OutOfMemoryException 之前释放 WeakReference 对象。可以在这里找到一个例子:http://developer.android.com/training/displaying-bitmaps/display-bitmap.html

【讨论】:

  • 这似乎很可能,但即使在我关闭应用程序后等待几分钟后,我仍然看到错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-19
  • 2012-11-20
  • 1970-01-01
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多