Android上的内存不足错误

4
我正在开发一款安卓游戏应用,其中有大约15个屏幕。当我连续玩时,我会随机遇到内存不足的错误问题,有时在第15个屏幕,有时在第12个屏幕左右。
此外,请查看下面的XML代码,其中包含一个屏幕的布局。
      <?xml version="1.0" encoding="UTF-8"?>
       <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
           android:id="@+id/MainFrame"
           android:layout_width="fill_parent"
           android:layout_height="fill_parent" >

   <RelativeLayout
       android:id="@+id/mainlayout"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:background="@drawable/woodenbg1" >

       <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:textSize="20sp"
        android:textStyle="bold"
        android:typeface="sans"
        android:visibility="gone" />

    <ImageView
        android:id="@+id/imageline"
        android:layout_width="10000dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="105dp"
        android:src="@drawable/lineblackfornormal" />

    <ImageView
        android:id="@+id/imageviewunderalphac"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="350dp"
        android:src="@drawable/whitec" />

    <ImageView
        android:id="@+id/backgroundofalphab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="35dp"
        android:src="@drawable/backgroundfordragimages"
        android:visibility="invisible" />

      <ImageView
          android:id="@+id/backgroundofalphaa"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginLeft="20dp"
          android:layout_marginTop="35dp"
          android:src="@drawable/backgroundfordragimages"
          android:visibility="invisible" />

       <ImageView
           android:id="@+id/backgroundofalphac"
           android:layout_width="100dp"
           android:layout_height="wrap_content"
           android:layout_alignParentRight="true"
           android:layout_marginTop="33dp"
           android:src="@drawable/backgroundfordragimages"
           android:visibility="invisible" />

       <ImageView
          android:id="@+id/imageviewunderleftalphab"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          android:layout_marginBottom="250dp"
          android:layout_marginLeft="15dp"
          android:src="@drawable/whiteb" />

      <ImageView
          android:id="@+id/imageviewunderrightalphaa"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          android:layout_alignParentRight="true"
          android:layout_marginBottom="250dp"
          android:layout_marginRight="10dp"
          android:src="@drawable/whitea" />

      <ImageView
          android:id="@+id/imageviewabovealphab"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_centerHorizontal="true"
          android:layout_marginTop="35dp"
          android:src="@drawable/colouredb" />

       <ImageView
          android:id="@+id/imageviewabovealphaa"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginLeft="20dp"
          android:layout_marginTop="35dp"
          android:src="@drawable/coloureda" />

       <ImageView
          android:id="@+id/imageviewabovealphac"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignLeft="@+id/backgroundofalphac"
          android:layout_marginTop="33dp"
          android:src="@drawable/colouredc" />
       </RelativeLayout>

     </FrameLayout>

日志

  05-16 12:22:18.989: E/GraphicsJNI(6745): VM won't let us allocate 2225664 bytes
  05-16 12:22:18.999: E/AndroidRuntime(6745): FATAL EXCEPTION: main
  05-16 12:22:18.999: E/AndroidRuntime(6745): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.Bitmap.nativeCreate(Native Method)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.content.res.Resources.loadDrawable(Resources.java:1709)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.content.res.Resources.getDrawable(Resources.java:581)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.view.View.setBackgroundResource(View.java:7533)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at com.ssn.myapp.NumbersLevel3.onCreate(NumbersLevel3.java:173)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2832)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread.access$1600(ActivityThread.java:117)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.os.Handler.dispatchMessage(Handler.java:99)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.os.Looper.loop(Looper.java:130)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at android.app.ActivityThread.main(ActivityThread.java:3683)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at java.lang.reflect.Method.invokeNative(Native Method)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at java.lang.reflect.Method.invoke(Method.java:507)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
  05-16 12:22:18.999: E/AndroidRuntime(6745):     at dalvik.system.NativeStart.main(Native Method)

你有没有尝试过 BitmapFactory.options? - Ronak Mehta
请查看此链接:http://osdir.com/ml/AndroidDevelopers/2009-08/msg01230.html - Ronak Mehta
@DevAndro 如果您能展示一些活动代码,那么会有所帮助。 - Raghunandan
2个回答

2

在不使用时回收位图。从蜂巢版本(Android 3.0)开始,位图会保留在堆上。

 bitmaps.recycle();

这个链接上有关于如何避免内存泄漏的主题。

此外,如果您拥有高分辨率图像,则应缩小比例。请参阅“将缩小的版本加载到内存中”主题。

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

假设您从Activity A导航到B。 在onResume()中加载位图。 在onPause()中回收位图。 对于每个加载位图的活动都要这样做。

您可以使用MAT Analyzer(如下面的视频所示)来分析和修复内存泄漏http://www.youtube.com/watch?v=_CruQY55HOk

您可以在应用程序标记下使用android:largeHeap。

警告:随着堆大小的增加,GC会更频繁地启动,应用程序也会更频繁地暂停。因此,仅仅因为您需要更大的堆而使用它是不明智的。您可以观看上面的视频,该人员对此进行了警告。

 android:largeHeap

是否应该使用大型Dalvik堆创建您的应用程序进程。这适用于为应用程序创建的所有进程。它仅适用于加载到进程中的第一个应用程序;如果您正在使用共享用户ID允许多个应用程序使用进程,则它们都必须始终使用此选项,否则它们将产生不可预测的结果。

大多数应用程序不需要此功能,而应专注于减少其整体内存使用量以提高性能。启用此功能也不能保证可用内存固定增加,因为某些设备受其总可用内存的限制。

要在运行时查询可用内存大小,请使用getMemoryClass()或getLargeMemoryClass()方法。


0

这是因为当您的活动被销毁时,您的图像没有被释放。

请参考this答案。还有this链接。

我认为在执行GC时不必担心细节,因为我们无法控制gc何时被调用。即使调用gc()也不能保证收集。根据System.gc()的文档。

内存已超出限制。GC会自动收集所有未使用的位图。所以我们必须自愿删除它

向虚拟机指示现在是运行垃圾回收器的好时机。请注意,这只是一个提示。不能保证实际上会运行垃圾回收器。

在开发具有大对象分配的应用程序时,我会关注以下内容:

  1. 当分配了大对象并在其生命周期范围内退出后,我是否会在后续的活动中看到它被GC回收?这可以通过在adb shell中使用dumpsys meminfo进行轻松检查。您可以在取消分配后检查内存是否被妥善垃圾收集,通常会出现大尖峰和之后的大降落。
  2. 检查这个大对象是否具有通往GC的明确路径。您可以通过转储hprof并在Memory Analyzer中检查此对象的引用路径来完成此操作。如果有的话,则安全,因为GC足够聪明地进行收集。
  3. 在分配此大对象后,我是否有足够的堆填充来执行后续活动?如果对象太大,有可能GC不足以快速进行收集(实际上与您的观点相关),并且来自后续活动的内存消耗与前几个活动中剩余的内存消耗结合起来可能会导致内存不足错误。设置具有通向GC的清晰路径的null将有助于确保此对象得到适当的GC。我承认这是一个问题,但我的观点是,如果这成为问题,我们可能必须重新审视该特定部分的设计,并查看是否可以对其进行优化。
  4. 根据需要通过onDestroy在活动中实现清理,并确保该活动没有被其他人引用,以便可以妥善进行垃圾收集。例如:我们经常传递活动上下文,忘记它将持有其引用。像在位图上调用recycle()之类的事情也应该有所帮助。记住这些要点应该有助于在发生#3的情况下准备更多的空间。

希望这能帮到您。


不,那不是问题所在。 应用程序超出堆中分配的内存。因此发生OOM错误。“这是因为你的图片在活动销毁时没有被释放。”这并不是问题所在。 - Raghunandan
当我连续播放时,会随机出现内存不足的错误问题。OP只是这样说的。这就是为什么我认为图像没有被释放。 - Gunaseelan
1
你能更清楚地解释这部分的意思吗?“图像没有被释放”。从logcat上看,是OOM。 - Raghunandan
根据logcat的显示,@Ginaseelan,这是OOM(Out Of Memory)错误,因为位图大小超过了VM预算,这意味着没有足够的空间来分配位图。您应该在不使用位图时回收它们。当gc启动时,它会释放内存。其次,他应该高效地加载位图(图像)。如果图像太大,他应该缩小图像。他应该在onResume()中加载位图,并在onPause()中回收它。这可以确保当gc启动并且活动被暂停时,内存被释放。 - Raghunandan
请参见我提供的链接 System.gc()。他们说“不能保证垃圾回收器实际运行”。 - Gunaseelan
显示剩余6条评论

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