从加载图片OOM说起

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.big);
        Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.big);
        Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.big);

创建三个 Bitmap,并且用引用引着,防止回收。

截图是 AS 上的内存监控,最大用内存 191 MB (说好的16MB呢)。

未创建图片时 9.7 MB,一张图 96 MB,两张图 175MB。

三张图就出现了 OOM 的情况:

java.lang.OutOfMemoryError: Failed to allocate a 82944012 byte allocation with 16777120 free bytes and 17MB until OOM

记住 82944012 ,等下回到这个数字。

位图是以怎么样形式存在在内存中?

Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
            boolean isMutable, boolean requestPremultiplied,
            byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
        mNativePtr = nativeBitmap;
        mFinalizer = new BitmapFinalizer(nativeBitmap);
    }
    public void recycle() {
        if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
            if (nativeRecycle(mFinalizer.mNativeBitmap)) {
                // return value indicates whether native pixel object was actually recycled.
                // false indicates that it is still in use at the native level and these
                // objects should not be collected now. They will be collected later when the
                // Bitmap itself is collected.
                mBuffer = null;
                mNinePatchChunk = null;
            }
            mRecycled = true;
        }
    }

关键是 natvieBitmap ,它应该指向了保存像素的空间,可能是个 byte 数组,我猜。

位图的大小

  /**
         * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
         * for translucency) is stored with 8 bits of precision (256
         * possible values.)
         *
         * This configuration is very flexible and offers the best
         * quality. It should be used whenever possible.
         */
        ARGB_8888   (5);

从 KITKAT 版本起,都是用 ARGB 8888,一像素 4 bytes。

82944012

3600 * 5760 * 4 正好是所需大小。

但是这张 big 的实际像素是:

高和宽都翻了 3 倍。

系统屏幕密度 Denstiy

可以参考:

http://blog.csdn.net/zhaoyw2008/article/details/46008513

举个例子

这里有两部手机,大小一样。

一号机,只有上下两个像素。二号机有八个像素。

如果只要展示纯色背景,比如 ColorDrawable,只要内存里保存一个颜色就行了。

但如果要展示一张上红下绿的位图,1号机需要保存两个像素(红,绿),2好号机需要保存八个像素(红,红,红,红,绿,绿,绿,绿)。

但在 drawable 文件夹只准备了 1*2 分辨率的图片,这是系统就会将位图进行适当的缩放,来满足的2号机的展示。

比如,分辨率高宽都乘以 2,颜色复制。

确定缩放比例的源码:

    public static Bitmap decodeResourceStream(Resources res, TypedValue value,
            InputStream is, Rect pad, Options opts) {

        if (opts == null) {
            opts = new Options();
        }

        if (opts.inDensity == 0 && value != null) {
            final int density = value.density;
            if (density == TypedValue.DENSITY_DEFAULT) {
                opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
            } else if (density != TypedValue.DENSITY_NONE) {
                opts.inDensity = density;
            }
        }

        if (opts.inTargetDensity == 0 && res != null) {
            opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
        }

        return decodeStream(is, pad, opts);
    }

inTargetDensity 会读取手机的密度。

而 TypeValue value 已经通过 native 方法取得 drawable 所在文件的 denstiy,

比如 mdpi (160)下的图片,在 xxhdpi (480)等级的手机上就会被放大 3 倍,就像这里的 big。

再举个例子,AS 默认的 icon 就为不同密度的手机准备了各自的版本:

前者密度,后者像素:160 48,240 72,320 96,480 144。

只要少了某一张图,其他的位图就可能被拿来缩放。

结尾

要是 OOM 了就是 Bitmap 使用不当。

不是 BitmapDrawable 的锅,也不是 ImageView 的锅。

时间: 2024-08-03 13:45:23

从加载图片OOM说起的相关文章

android 加载图片oom若干方案小结

本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结. 众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定).一般我们可以通过获取当前线程的可运行内存来判断,比如系统分给当前运行内存只有16M,而你的图片就有16M,这肯定会oom的. 相关知识介绍 1.颜色模型 常见的颜色模型有RGB.YUV.CMYK等,在大多数图像API中采用的都是RGB模型,Android也是如此:另外,在Android中还有包含透明度Alpha的颜色模型

Android开发解决加载图片OOM问题(非常全面 兼顾4.0以下系统)(by 星空武哥)

转载请标明:http://blog.csdn.net/lsyz0021/article/details/51295402 我们项目中经常会加载图片,有时候如果加载图片过多的话,小则导致程序很卡,重则OOM导致App挂了,今天翻译https://developer.Android.com/training/displaying-bitmaps/index.html,学习Google高效加载大图片的方法. 图片有各种形状和大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库

Android之批量加载图片OOM问题解决方案

一.OOM问题出现的场景和原因 一个好的app总少不了精美的图片,所以Android开发中图片的加载总是避免不了的,而在加载图片过程中,如果处理不当则会出现OOM的问题.那么如何彻底解决这个问题呢?本文将具体介绍这方面的知识. 首先我们来总结一下,在加载图片过程中出现的OOM的场景无非就这么几种: 1.  加载的图片过大 2.  一次加载的图片过多 3.  以上两种情况兼有 那么为什么在以上场景下会出现OOM问题呢?实际上在API文档中有着明确的说明,出现OMM的主要原因有两点: 1.移动设备会

Andorid Volley框架加载图片OOM问题分析

一.Volley框架简介 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,Google 在2013年的I/O大会 上,发布了Volley.Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮. Volley提供了JsonObjectRequest.JsonArrayRequestStringRequest等Request形式

ViewPager做图片浏览器,加载大量图片OOM的问题修正

1 /** 2 * @author CHQ 3 * @version 1.0 4 * @date 创建时间: 2016/7/26 17:18 5 * @parameter 6 * @return 7 * 图片查看器 8 * //可以查看网络图片 9 * //可以查看本地图片 10 */ 11 public class PhotoScan extends Activity { 12 private PhotoViewPager mViewPager; 13 private List<View>

android 图片加载,OOM 问题

首先处理这个问题,用了1个星期,非常努力,拼命的寻找哪里出现了OOM 内存溢出的问题,可是都没找到结果,一直以为是自己使用的Picaso加载图片框架,只加载了图片,但是activity 销毁时,没有做内存释放的功能,所以自己去尝试方法去解决问题: 1.换一个图片框架:Xutil 图片框架 结果只是换汤不换药. 还是会出现OOM ,内存溢出问题 2.图片单独处理:网上说针对于大图,要做缩放处理,并对生成的BitMap 对象进行内存处理 private void initDisplayImageOp

Android 大图片加载 避免OOM

文章来自郭大神:======= 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9316683 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/training/displaying-bitmaps/index.html 高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.

软引用SoftReference异步加载图片

HashMap<String, SoftReference<Drawable>> imageCache 关于SoftReference这个类多少知道些机制,会用就ok了. 机制:简单来说,她会帮助我们管理内存,防止内存溢出,另外一点也就相当于map,临时缓存些图片drawable让我们可以直接引用,很好了解决了OOM异常. 实现代码片段: [java]package com.Tianyou.Mobile.Common;  import java.io.IOException; im

续说ListView重用之加载图片

最近领养了一直小狗狗,据狗主人说是只阿拉斯加,求大伙见证. 不管他是不是阿拉斯加,我还是得养着,取名"蛋蛋". 继续谈技术. 说到listview里加载图片永远是个说不完的话题. 在listview中如果每个item都有图片需要下载的话,我们就得考虑由于大量图片加载而导致的oom(out of memory)问题. 一个典型的做法是,下载图片的时候看看缓存中有没有该图片,如果缓存中没有,就从sd卡中读取,如果sd卡中还没有,再去服务器下载,下载下来的图片先放在sd卡中,并放到缓存中.如