目录介绍

  • 7.0.0.1 加载bitmap图片的时候需要注意什么?为何bitmap容易造成OOM?如何计算Bitmap占用内存?
  • 7.0.0.2 如何理解recycle释放内存问题?图片加载到内存其实有两部分数据,这是为何?
  • 7.0.0.3 如何在不压缩图片的情况下加载高清大图?加载图的机制是什么,为何不会内存泄漏?
  • 7.0.0.7 LRU算法的原理?核心思想是什么?如果缓存满了的话,什么方法来管理移除最近最少使用的item和添加新的item?

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有的笔记将会更新到GitHub上,同时保持更新,欢迎同行提出或者push不同的看法或者笔记!

7.0.0.1 加载bitmap图片的时候需要注意什么?为何bitmap容易造成OOM?如何计算Bitmap占用内存?

  • 注意问题

    • 直接加载大容量的高清Bitmap很容易出现显示不完整、内存溢出OOM的问题,所以最好按一定的采样率将图片缩小后再加载进来
    • 为减少流量消耗,可对图片采用内存缓存策略,又为了避免图片占用过多内存导致内存溢出,最好以软引用方式持有图片
    • 如果还需要网上下载图片,注意要开子线程去做下载的耗时操作技术博客大总结
  • 为何bitmap容易造成OOM
  • 如何计算Bitmap占用内存
    • 1.1 如何计算占用内存

      • 如果图片要显示下Android设备上,ImageView最终是要加载Bitmap对象的,就要考虑单个Bitmap对象的内存占用了,如何计算一张图片的加载到内存的占用呢?其实就是所有像素的内存占用总和:
      • bitmap内存大小 = 图片长度 x 图片宽度 x 单位像素占用的字节数
      • 起决定因素就是最后那个参数了,Bitmap'常见有2种编码方式:ARGB_8888和RGB_565,ARGB_8888每个像素点4个byte,RGB_565是2个byte,一般都采用ARGB_8888这种。那么常见的1080*1920的图片内存占用就是:1920 x 1080 x 4 = 7.9M
    • 1.2 上面方法计算内存对吗
      • 我看到好多博客都是这样计算的,但是这样算对吗?有没有哥们试验过这种方法正确性?我觉得看博客要对博主表示怀疑,论证别人写的是否正确。更多详细可以看我的GitHub:https://github.com/yangchong211

        • 说出我的结论:上面1.1这种说法也对,但是不全对,没有说明场景,同时也忽略了一个影响项:Density。接下来看看源代码。
        • inDensity默认为图片所在文件夹对应的密度;inTargetDensity为当前系统密度。
        • 加载一张本地资源图片,那么它占用的内存 = width * height * nTargetDensity/inDensity * nTargetDensity/inDensity * 一个像素所占的内存。
        @Nullable
        public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
        @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
        validate(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);
        }
      • 正确说法,这个注意呢?计算公式如下所示
        • 对资源文件:width * height * nTargetDensity/inDensity * nTargetDensity/inDensity * 一个像素所占的内存;
        • 别的:width * height * 一个像素所占的内存;
    • 1.3 一个像素占用多大内存技术博客大总结
      • Bitmap.Config用来描述图片的像素是怎么被存储的?

        • ARGB_8888: 每个像素4字节. 共32位,默认设置。
        • Alpha_8: 只保存透明度,共8位,1字节。
        • ARGB_4444: 共16位,2字节。
        • RGB_565:共16位,2字节,只存储RGB值。

7.0.0.2 如何理解recycle释放内存问题?图片加载到内存其实有两部分数据,这是为何?

  • 如何理解recycle释放内存问题?

    • 在Android2.3.3(API 10)及之前的版本中,Bitmap对象与其像素数据是分开存储的,Bitmap对象存储在Dalvik heap中,而Bitmap对象的像素数据则存储在Native Memory(本地内存)中或者说Derict Memory(直接内存)中,这使得存储在Native Memory中的像素数据的释放是不可预知的,我们可以调用recycle()方法来对Native Memory中的像素数据进行释放,前提是你可以清楚的确定Bitmap已不再使用了,如果你调用了Bitmap对象recycle()之后再将Bitmap绘制出来,就会出现”Canvas: trying to use a recycled bitmap”错误,而在Android3.0(API 11)之后,Bitmap的像素数据和Bitmap对象一起存储在Dalvik heap中。
  • 图片加载到内存其实有两部分数据,这是为何?技术博客大总结
    • 一个图片加载到内存里,其实是有两部分数据组成,一部分是图片的相关描述信息,另一部分就是最重要的像素信息(这部分是有byte数组组成的),android系统为了提高对图片的处理效率,对于图片的处理都是调用了底层的功能(由C语言实现的),也就是说一个图片加载到内存里后是使用两部分的内存区域,简单的说:一部分是java可用的内存区,一部分是c可用的内存区,这两个内存区域是不能相互直接使用的,这个bitmap对象是由java分配的,当然不用的时候系统会自动回收了,可是那个对应的C可用的内存区域jvm是不能直接回收的,这个只能调用底层的功能释放。所以你要调用recycle方法来释放那一部分内存。
  • 查看源码如下所示
    • 翻译这段解释:释放bitmap内存的时候,它会释放和这个bitmap有关的native内存,同时它会清理有关数据对象的引用,但是这里处理数据对象的引用,并不是立即清理数据(他并不是调用玩recycle()方法,就直接清理这个内存,他只是给垃圾回收机制发送一个指令,让它在bitmap没有对象引用的时候,来进行垃圾回收)。当调用recycle()方法之后,这个bitmap就会被表明为“死亡状态”。这个时候你在调用bitmap其他相关的方法,例如果get像素()或set像素()就会抛出一个异常。同时这个操作是不可逆的,所以一定百分之百确定这个bitmap在以后的场景下,不会被你的程序在使用到,再去调用recycle()方法。所以谷歌源码中建议我们,可以不用去主动调用recycle()方法,因为在没有引用的情况下,我们的垃圾回收机制会主动的清理内存。
    • 通过看源码,我们会发现,这个方法首先将这个Bitmap的引用置为null,然后调用了nativeRecycle(mNativeBitMap)方法,这个方法很明显是个JNI调用,会调用底层的c或者c++代码就可以做到对该内存的立即回收,而不需要等待那不确定啥时候会执行的GC来回收了。

7.0.0.3 如何在不压缩图片的情况下加载高清大图?加载图的机制是什么,为何不会内存泄漏?

  • 如何在不压缩图片的情况下加载高清大图?

    • 使用BitmapRegionDecoder,主要用于显示图片的某一块矩形区域,如果你需要显示某个图片的指定区域,那么这个类非常合适。
  • 加载图的机制是什么,为何不会内存泄漏?
  • 自定义可拖动的显示高清大图的View技术博客大总结
    • 提供一个设置图片的入口,setInputStream里面去获得图片的真实的宽度和高度,以及初始化我们的mDecoder
    • 重写onTouchEvent,在里面根据用户移动的手势,去更新显示区域的参数。在onMeasure里面为我们的显示区域的rect赋值,大小为view的尺寸
    • 每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,然后draw。

7.0.0.7 LRU算法的原理?核心思想是什么,谈谈你的思路?

  • 为减少流量消耗,可采用缓存策略。常用的缓存算法是LRU(Least Recently Used):

    • 核心思想:当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:

      • LruCache(内存缓存):LruCache类是一个线程安全的泛型类:内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,并提供get和put方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。
      • DiskLruCache(磁盘缓存): 通过将缓存对象写入文件系统从而实现缓存效果
  • 大概过程如下?技术博客大总结
    • LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。它把最近使用的对象用“强引用”存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前就从内存中移除。
  • 如果缓存满了的话,什么方法来管理移除最近最少使用的item和添加新的item?
    • trimToSize()方法,删除最年长的条目,直到剩余条目的总数达到或低于请求的大小

      public void trimToSize(int maxSize) {
      while(true) {
      Object key;
      Object value;
      synchronized(this) {
      if (this.size < 0 || this.map.isEmpty() && this.size != 0) {
      throw new IllegalStateException(this.getClass().getName() + ".sizeOf() is reporting inconsistent results!");
      } if (this.size <= maxSize || this.map.isEmpty()) {
      return;
      } Entry<K, V> toEvict = (Entry)this.map.entrySet().iterator().next();
      key = toEvict.getKey();
      value = toEvict.getValue();
      this.map.remove(key);
      //计算现在缓存的大小,然后减掉多余的,内部调用的是sizeOf()方法
      this.size -= this.safeSizeOf(key, value);
      ++this.evictionCount;
      } //如果你想在在我们的缓存中实现二级缓存,可以实现此方法,源码中是空方法。
      this.entryRemoved(true, key, value, (Object)null);
      }
      }

关于其他内容介绍

01.关于博客汇总链接

02.关于我的博客

07.Android之多媒体问题的更多相关文章

  1. Android官方多媒体API Mediacodec翻译(一)

    因近期工作调整,关于Mediacodec部分的翻译会暂停,后续有时间一定补上,非常抱歉. 本文章为根据Android Mediacodec官方英文版的原创翻译,转载请注明出处:http://www.c ...

  2. Android的多媒体框架OpenCore介绍

    网上资料很少, 不过还是找到一个比较详细的说明: 特地在此整理了下: 地址:http://blog.csdn.net/djy1992/article/details/9339787 分为几个阶段: 1 ...

  3. Android开发多媒体应用之SoundPool的使用的代码

    内容过程中,把写内容过程中比较好的内容段记录起来,下面的内容是关于Android开发多媒体应用之SoundPool的使用的内容,希望对各位也有用途. public class MainActivity ...

  4. android之多媒体篇(一)

    Android 4.0.3(Api Level 15)支持的多媒体格式. 注意:有些设备可能支持其他的文件格式. 1.Audio AAC LC/LTP.HE-AACv1(AAC+).AMR-NB.AM ...

  5. android之多媒体篇(二)

    管理音频焦点 情景:当你的app隐退到后台,而其他也有播放能力的app浮现在前台,这个时候,你可能要暂停你原有app的播放功能,和解除监听Media Button,把控制权交给前台的APP. 这就需要 ...

  6. android之多媒体篇(三)

    录像 Android提供了2种方案去录像. 方案一: 最简单的方式就是使用Intents去启动App来帮助你完成.这个方案使你能够指定输出的位置和视频的质量.这方案通常是最好的方法,应该可以用在多种情 ...

  7. Android之多媒体扫描过程

    转自:http://blog.csdn.net/yan8024/article/details/6620359下面是系统图      MediaScannerReceiver会在任何的ACTION_B ...

  8. Android开发 多媒体提取器MediaExtractor详解_入门篇

    前言 MediaExtractor字面意思是多媒体提取器,它在Android的音视频开发里主要负责提取视频或者音频中的信息和数据流(例如将视频文件,剥离出音频与视频).本章博客将讲解一些入门简单的东西 ...

  9. Android引用多媒体

    res目录下,创建raw目录(Android会自动识别这个目录),如果自己创建的目录,可能无效底下的mp3格式,mp4格式的文件名必须小写. 引用方式: mediaPlayer = MediaPlay ...

  10. Android开发 多媒体提取器MediaExtractor详解_将一个视频文件分离视频与音频

    前言 此篇博客讲解MediaExtractor将一个视频文件分离视频与音频,如果你对MediaExtractor还没有一个笼统的概念建议先了解我的另一篇入门博客:https://www.cnblogs ...

随机推荐

  1. JS script脚本async和defer的区别

    壹 ❀ 引 我在 google recaptcha 谷歌人机身份验证使用教程 一文中有引用这样一段外部资源代码,如下: <script src="https://www.google. ...

  2. MySQL基础之DDL语句

    讲解SQL语句三大分类和每个分类的SQL使用入门. 使用的是数据库是:MySQL 8.0.27 1.SQL分类   DDL(Data Definition Language)语句:数据定义语句. 用途 ...

  3. 深入 Nginx 之架构篇[转]

    前言 最近在读 Nginx 相关的书籍,做一下读书笔记. Nginx 作为业界知名的高性能服务器,被广泛的应用.它的高性能正是由于其优秀的架构设计,其架构主要包括这几点:模块化设计.事件驱动架构.请求 ...

  4. 对称加密算法汇总:AES DES 3DES SM4 java 实现入门

    密码的世界 如果你是黑帮老大,平时和手下沟通,如何保证自己的信息安全呢? 在神探夏洛克的第一季中,就讲述了一个如何侦破黑帮的加密交流的故事. 这种密码利用的是密码字典. 密码本身可以是一本书,比如常见 ...

  5. Ubuntu20.04和22.04离线安装PostgreSQL14

    今天安装 Postgresql14 遇到一个问题, 目标服务器只有内网, 内网提供标准的apt仓库, 但是因为不能连接外网, 所以没法添加第三方仓库, 这样安装pg14就成了问题. 从pg的官网看, ...

  6. Ubuntu下图形界面串口工具CuteCom的安装和升级

    串口的图形界面化工具在Windows下很多, 但是在Linux下可选择的就很少, CuteCom 是相对比较好用的一款了. Ubuntu20.04默认安装的是0.30.3, 这是一个比较早的版本, 最 ...

  7. 基于keras的残差网络

    1 前言 理论上,网络层数越深,拟合效果越好.但是,层数加深也会导致梯度消失或梯度爆炸现象产生.当网络层数已经过深时,深层网络表现为"恒等映射".实践表明,神经网络对残差的学习比对 ...

  8. maven打包时打包指定的lib文件夹

    今天在打包自己的spring boot项目时遇到了问题, 报找不到类和符号. 因为我有些依赖是放在项目lib文件夹中,那么打包的时候要连把它一起打包. 修改pom.xml, 添加一下内容: <b ...

  9. Java并发编程实例--9.使用本地线程变量

    并发程序一个重要方面就是共享数据. 这一点在继承了Thread类或实现了Runnable接口的对象中有着特殊的重要性. 如果你创建了一个实现了Runnable接口的类对象并且用这个对象开启了N个线程对 ...

  10. SpringCloud SpringBoot 组件使用:SpringBoot Actuator

    基础篇 一.什么是Spring Actuator? spring-boot-starter-actuator模块是一个spring提供的监控模块.我们在开运行发过程中,需要实时和定时监控服务的各项状态 ...