【问题标题】:Trying to prevent OutOfMemoryError seeing MAT - Android试图防止 OutOfMemoryError 看到 MAT - Android
【发布时间】:2014-08-19 16:42:39
【问题描述】:

我试图在我的 android 应用程序中防止 OutOfMemoryError。看了很多帖子,还是解决不了。

该应用程序有后台活动,所以我认为这是主要问题。 OutOfMemoryError 仅在某些设备中发生(可能是由于 VM 堆),我需要确保此错误不会在任何设备中导致崩溃。

我最近阅读了关于 MAT(Memory Analytics 插件)的信息,并且在应用运行时执行了它,您可以在这里看到结果:

支配树

报告

在这个活动中,我为每个方向(家庭、家庭土地)设置了一个背景。两种尺寸相同(190kb,jpg)。当我创建 HPROF 文件时,活动是横向的,我之前没有运行纵向。为了达到我的目的,我可以从这个结果中得出什么结论?

如有必要,我可以添加更多信息

编辑

我也尝试使用this page的方法来避免OutOfMemoryError,但我无法得到它。这是我的代码:

decodeFromResource 类

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class decodeFromResource {

    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {

        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static Drawable getDecodedDrawableFromResource(Resources res, int resId,
            int reqWidth, int reqHeight){
        return new BitmapDrawable(res, decodeSampledBitmapFromResource(res, resId, reqWidth, reqHeight));
    }
}

来自主活动的 onCreate 方法

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.home);

        resources = getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();

        layoutHome = (LinearLayout) findViewById(R.id.home_layout);
        if (resources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            layoutHome.setBackgroundDrawable(decodeFromResource
                    .getDecodedDrawableFromResource(resources, R.drawable.home,
                            metrics.widthPixels, metrics.heightPixels));
        } else {
            layoutHome.setBackgroundDrawable(decodeFromResource
                    .getDecodedDrawableFromResource(resources,
                            R.drawable.home_land, metrics.heightPixels,
                            metrics.widthPixels));
        }

我只为背景实现了“有效加载大位图”方法,因为除此之外我只有五个非常小的小按钮。我是否还需要为他们实施该方法?你能看到任何错误吗?

【问题讨论】:

  • 您在启动时或在纵向和横向之间反复切换时会出现 OOM 吗?
  • @Hans Kratz 这取决于设备。有时在启动 Home Intent 后我会得到 OOM,但有时它只在我切换方向时发生。

标签: android out-of-memory heap-memory


【解决方案1】:

您可能正在按原样加载 jpg 文件,即使在强大的设备上也很容易导致 OutOfMemory。

请记住,在没有压缩的情况下加载到内存中的图像,并且在大多数设备上,单个像素由 4 个内存字节表示。例如,一个 7 MPixel 的图像需要 28 MByte 的内存块,这可能会使您的应用真正接近 OutOfMemory 崩溃。

解决方案很简单:始终根据应用的需要加载缩小的图像。

首先要阅读您的图片尺寸:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

上面的代码不会加载实际的图像文件。它只会审问它 因为它的尺寸。

一旦你有了deminsion,你就可以计算出要用于的“样本量” 加载缩放的图像。样本大小为 N 将导致加载 1/(N*N) 的 原始图像像素,例如对于 4 的样本大小,只会加载 1/16 的图像像素。

最后加载缩小的图片:

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

options.inSampleSize = mySampleSize; //<-----------------------

options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeResource(res, resId, options);

即使在进行按比例缩小的加载时,最好使用以下方法保护您的代码 一个 try {...} catch(OutOfmemory) 子句并允许优雅地处理加载失败。

更多详情:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

【讨论】:

  • 感谢@Gilad Haimov 提供的代码,但我尝试了相同的解决方案,但没有解决任何问题。我将发布我使用的方式。请告诉我您是否可以看到任何错误。再次感谢。
【解决方案2】:

最后,在我阅读了很多帖子之后,我在@j__m 答案中的最后评论是正确的。问题在于可绘制文件夹。

我发现了这个:https://stackoverflow.com/a/19196749/2528167

“选项 #1:只需发布 -xxhdpi 可绘制对象并让 Android 在运行时为您对它们进行下采样(缺点:仅适用于已知 -xxhdpi 的最新设备)。”

我将所有图片放在 xxhdpi 文件夹中,以便让 Android 在运行时对它们进行下采样,但正如 CommonsWare 所说,这仅适用于最近的设备,所以我填充了 drawable-**dpi 文件夹,现在 OutOfMemoryError 没有出现.

【讨论】:

    【解决方案3】:
    options.inPurgeable = true;
    options.inInputShareable = true;
    

    这些标志允许与Bitmap 对象关联的实际位在内存压力下被丢弃,并在发现您仍在使用Bitmap 时透明地重新解码。

    【讨论】:

    • 如果您仍然收到OutOfMemoryError,那么它与您的位图无关。因此,我们陷入了僵局;这里没有足够的信息来怀疑还有什么问题。
    • 我不知道,但是如果您的应用程序很复杂并且只发生在某些设备上(由于 vm 堆大小),那么您可能没有任何替代方案来使用 sroka 建议的大堆.
    • 如果您有未使用 decodeFromResource 代码加载的位图 - 例如,因为您在 xml 中设置了它们 - 那么您绝对应该根据目标设备的分辨率。如果您的 drawable-xxhdpi 位图是 144x144,那么您应该有一个 96x96 的 drawable-xhdpi 位图、一个 72x72 的 drawable-hdpi 位图和一个 48x48 的 drawable-mdpi 位图。
    • 通常您的布局元素的大小以dp 为单位,因此应使用drawable-***dpi 文件夹。 -large-xlarge 等文件夹根本不应该使用;如果您需要根据屏幕大小(通常是布局,而不是可绘制对象)进行更改,那么您应该使用-w***dp-h***dp-sw***dp 语法来更准确地指示资源之间的切换点。
    • 总结:旧式-large等和新式-w***dp等是基于屏幕的物理尺寸,而不是特定图形将占用的像素数.使用-***dpi 文件夹根据屏幕分辨率提供正确的像素数。
    【解决方案4】:

    我觉得你在使用Bitmap之类的DecodeResource的时候,最好人为的使用GC,如果不这样做,可能会OOM。

    【讨论】:

      【解决方案5】:

      尝试在您的 AndroidManifest.xml 中使用 android:largeHeap="true" 标记,这应该确保 android 能够处理更大的位图。

      编辑

      我必须指出,这不是您问题的最终解决方案,它不会阻止 OutOfMemory 异常,但它们出现的可能性较小。可能 Gilad Haimov 发布了解决此问题的正确方法

      【讨论】:

      • 感谢您的回答 Sroka 但我认为这是错误的方式。正如@Gilad Haimov 所说,最好尝试有效地加载位图。
      • 我明白你明白我的意思:)。我已回复@Gilad Haimov。看看并告诉我你是否也能发现任何错误。
      • 您发表了评论,我相互编辑了 :) 我只需要说清楚。但是仍然使用这个标签应该会有所帮助,因为您不必经常处理 OOM 异常
      【解决方案6】:

      由于位图已解压,190kb 的存储空间并没有真正的帮助,您是否只是加载位图而几乎不考虑操作适合内存分页要求的参数?大约屏幕分辨率的图像可以直接加载而无需考虑内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-20
        • 2016-03-29
        • 2018-02-10
        • 2011-08-25
        • 2011-02-28
        • 2013-08-31
        • 2013-05-16
        相关资源
        最近更新 更多