安卓应用程序重新启动时崩溃,提示内存不足。

3
所以我遭遇了因大型位图引起的臭名昭著的oom错误。但我已经成功解决了大部分问题。唯一剩下的问题是,当我点击返回并关闭应用程序,然后立即启动应用程序时,应用程序将崩溃并显示oom(内存不足)错误。如果我点击主页,则不会发生这种情况。
为什么会出现这种情况?我的猜测是GC没有完成清理工作,现在我启动它时旧数据还在那里。当然,这不是一个新应用程序,所以旧启动和新启动都在同一个应用程序内存限制下运行。
对于此问题和可能的解决方案,任何输入都将是很好的。
我尝试过的:
对于所有位图下载,我使用了:
BitmapFactory.Options op = new Options();
op.inPurgeable = true;
bmImg = BitmapFactory.decodeStream(is,null,op);

使图像在宽度 x 高度方面的尺寸更小(大约相同大小的 kb)。<--这解决了该问题,所以我有一个备用解决方案,除非有人有超级解决方案 :)
错误日志片段:
06-25 04:29:28.917: E/AndroidRuntime(8819): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:715)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.content.res.Resources.loadDrawable(Resources.java:1713)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.widget.ImageView.<init>(ImageView.java:122)
06-25 04:29:28.917: E/AndroidRuntime(8819):     at android.widget.ImageView.<init>(ImageView.java:112)
06-25 04:29:28.917: E/AndroidRuntime(8819):     ... 23 more

编辑: 有两个方法可以解决我的问题。

  1. 在我的主活动的ondestroy()中清除数据库并将大图像设置为null。
  2. 将大图像变小。

但这只是引起了同样根本的问题,如果onDestroy()被调用,为什么我的活动没有在新活动打开之前正确关闭?我发现我的活动在关闭后仍然持续运行很长时间。这是否与该问题有关?我如何找出其原因?

编辑2:罪魁祸首似乎是我的LruCache。我使用一个静态lrucache,在ondestroy()中没有清除它。当应用程序重新启动时,lrucache中的所有图像仍然存在,这会导致问题。我仍然想知道为什么这只是在重新启动时才成为问题?在我关闭主要活动之前返回时,这不也应该是一个问题吗?


这可能是在位图解码时出现文件大小较大的问题,因此您可以尝试查看以下帖子以获取有关位图大文件大小解码的解决方案:https://dev59.com/puo6XIcBkEYKwwoYTzNK#823966。欢迎! - Dinesh
3个回答

2

我曾经遇到过同样的问题,通过强制关闭进程解决了。可以通过覆盖onDestroy()方法来实现。使用以下代码:

@Override
public void onDestroy(){
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> pids = am.getRunningAppProcesses();
    for (int i = 0; i < pids.size(); i++) {
        ActivityManager.RunningAppProcessInfo info = pids.get(i);
        if (info.processName.equalsIgnoreCase(context.getPackageName())) {
            android.os.Process.killProcess(info.pid);
        }
    }
    super.onDestroy();
}

这可能会起作用,但我想我会尝试找到使我的应用程序无法正确关闭的参考资料。 - Warpzit
经过一些阅读(包括commonsware在内),我不会走这个方向。这可能会引起各种其他问题。 - Warpzit
我理解你的顾虑,但是我还没有找到更好的解决方案。 - Behzad Momahed Heravi
我更喜欢“Android”的方式,让系统关闭我的应用程序。我发现的问题是静态变量在应用程序关闭时不会被清除。因此,针对我的问题,我会确保在ondestroy()中将这些变量设置为null。 - Warpzit

1

嘿,请检查我在同一问题上的答案:bitmap size exceeds Vm budget error android

并且在处理像这样的位图时,始终尝试使用最大选项:

        final Options options = new Options();
        options.outHeight = (int) scaleHeight; // new smaller height
        options.outWidth = (int) scaleWidth;   // new smaller width
        options.inScaled = true;
        options.inPurgeable = true;

        // to scale the image to 1/8
        options.inSampleSize = 8;
        bitmap = BitmapFactory.decodeFile(imagePath, options);

这可能会解决您的问题。


我已经使用了inPurgeable。inSampleSize会降低质量,这不是一个选项。我需要以原始尺寸获取图像。 - Warpzit
如果您的图像大小非常大,例如2到3 mb,则加载这些图像将导致此错误。请检查图像的大小是否合适。同时,请检查您的代码是否存在任何内存泄漏,这也可能是问题的原因。 - Shrikant Ballal
如果图像不是很大,那么请检查WeakReference。并且当您处理位图时,请尽快调用其recycle()方法。 - Shrikant Ballal
我使用一个lrucache来存储从网络下载的所有图像等。问题发生在应用程序重新启动时,需要创建一个大的轮廓图像。 - Warpzit
当然。如果你得到了答案,别忘了更新这篇帖子。祝一切顺利。 - Shrikant Ballal
显示剩余3条评论

0

罪魁祸首似乎是我的LruCache。我使用一个静态的lrucache,在ondestroy()中没有被清除。当应用程序重新启动时,lrucache中的所有图像仍然存在,这会导致问题。我仍然想知道为什么这只在重新启动时成为问题?在我关闭主活动之前返回主活动时,这不应该也是一个问题吗?

尽管如此,我对这个问题的临时/永久解决方案是在ondestroy()中清除所有静态引用,同时使用较小尺寸的图像。这似乎解决了我所有的问题,因为我也找不到任何内存泄漏。


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