Android内存优化

什么是内存泄漏和内存溢出?

内存泄漏:memory leak
程序申请内存后,被某个其他对象一直持有,无法释放已申请的内存空间。(内存只进不出)

内存溢出:out of memory
当内存一直被申请,却得不到释放,内存空间太小。当程序在申请内存时,没有足够的空间供其使用,就出现OOM。

注意:内存泄漏/溢出不能try catch处理。

产生的原因和解决方法

  • 大图片和多图片的优化
    图片如果太大,加载到内存时可能导致OOM。
    解决:

    • 合理使用JPG和PNG

      • JPG内存小,但解码复杂
      • PNG内存大,但解码简单。如果PNG图片过多,会造成频繁GC,甚至OOM。
    • 图片压缩:

      • createScaledBitmap();现成的API,但是这个API的使用前提条件是图片需要先加载到内存中。
      • 还有一个经常使用到的技巧是inJustDecodeBounds,可以事先获取到图片的大小。需要设置bitmapOptions.inJustDecodeBounds = true;
      • 降低分辨率
      • 指定解码方式:
        • Bitmap.Config ARGB_8888 默认,一个像素点占32位,最占内存的
        • Bitmap.Config ARGB_4444 一个像素点占16位
    • bitmap对象不使用时,要recycle()释放内存

    • 尽量使用RecyclerView或者ListView替换ScrollView

    • 聊一下图片的三级缓存

      • 目的:减少不必要的流量消耗,增加加载速度
      • 原理:
        • 一级缓存–>内存,LruCache,采用最近最少原则,把最近使用的通过LinkedhashMap来强引用持有,把最少使用的对象在缓存值达到预设值之前就从内存中移除
        • 二级缓存–>本地,DiskLruCache,
        • 三级缓存–>网络
      • 流程:先从内存加载,内存中有,就直接加载;内存中没有,就从本地加载,若本地中有,加载的同时缓存到内存;若本地也没有,从网络加载,同时缓存到内存和本地。
      • Glide自带三级缓存
        • skipMemoryCache(false),默认false,自动开启内存缓存。
        • diskCacheStrategy(DiskCacheStrategy.RESULT),开启硬盘缓存
          DiskCacheStrategy.NONE: 表示不缓存任何内容
          DiskCacheStrategy.SOURCE: 表示只缓存原始图片
          DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)
          DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片
    • 聊一下图片加载框架

      • Glide:
        可以处理大型的图片流,图片自动缩放的
      • Picasso:
        体积非常小,图片未缩放的
      • Fresco:
        体积非常大,图片存储在系统的匿名共享内存,而不是dalvik heap内存中,所以不会导致OOM,减少了频繁GC,性能更高。
  • 强引用、软引用、弱引用、虚引用

    • 强引用:
      直接new出来的对象
      String str = new String(“aaa”);
      特点:对象任何时候都不会对系统回收,JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。

    • 软引用:SoftReference
      String str = new String(“aaa”);
      SoftReference s = new SoftReference(str);
      if(s.get() != null){ // 一定要判空
      String softStr = s.get();
      }
      特点:内存空间足,不回收;内存空间不足,就会回收

    • 弱引用:WeakReference
      String str = new String(“aaa”);
      WeakReferences = new WeakReference(str);
      if(s.get() != null){ // 一定要判空
      String weakStr = s.get();
      }
      特点:无论内存空间是否足够,只要发现,就会回收

    • 虚引用:PhantomReference
      特点:可以在任何时候被回收,无法通过get()方法来获取对象实例。仅仅只能在对象被回收时收到一个通知。

    我们知道,java的Object类里有个finalize()方法,它的工作原理是:一旦该对象即将被回收,会调用其finalize()方法,并且在下一次真正回收动作发生时,才会真正的回收它。
    但是问题在于,GC时间是随机的,finalize()方法被调用时间也是随机的,使用虚引用就可以解决这个问题。虚引用可以精细的跟踪内存使用情况。

    到底什么时候用软引用,什么时候用弱引用?
    1,如果只是想避免OOM,则可以使用软引用;如果对应用的性能更在意,则可以使用弱引用。
    2,根据对象是否经常被使用。如果对象经常被使用,则尽量用软引用,否则使用弱引用。

  • 单例导致的
    单例的静态特性使其生命周期和应用一样长,所以传入的context的生命周期至关重要,一定要传入Application的Context,而不是Activity的Context。

  • 在非静态类里创建静态实例
    该静态实例生命周期和应用一样长,导致了该静态实例一直持有该Activity的引用,该Activity销毁后内存资源不能正常回收。

    要么去掉static,要么将this换成Application的Context
    在这里插入图片描述

  • 用非静态内部类创建其静态实例
    非静态内部类会默认持有外部类的引用,而又使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。

    要么将该内部类设为静态内部类,因为静态的内部类不会持有外部类的一个隐式引用;要么将该内部类抽取出来,如果需要使用Context,需要使用ApplicationContext 。
    在这里插入图片描述

  • 异步任务导致的
    若Activity已经销毁,但是异步任务还没结束,需要将AsyncTask、Thread等设为静态内部类,而且需要在Activity销毁时取消相应的异步任务。

  • Handler导致的
    Handler是非静态匿名内部类,持有Activity的引用,虽然Handler实例不是静态的,但是消息队列是在Looper线程中不断轮询处理消息的,当Activity销毁,消息队列中还有未处理的消息,消息队列中的Message持有Handler实例的引用,Handler又持有Activity的引用,就会导致Activity内存资源无法正常回收。

    将Handler设为静态内部类,传入的Context可以使用ApplicationContext,也可以将Context弱引用,而且需要在Activity销毁时移除消息队列中的消息,handler.removeCallbacksAndMessages。

  • 动画导致的
    属性动画中可以设置无限循环动画,该View持有该Activity对象的引用

    需要在Activity销毁时停止动画,objectAnimator.cancel()。

  • 资源未关闭导致的
    IO流未关闭、BroadcastReceiver未注销、Bitmap未释放等。

  • 第三方库导致的
    EventBus,RxJava等,在Activity销毁时需要解除订阅

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一些Android内存优化的方法: 1. 使用Android内存管理工具 Android提供了一些内存管理工具,如hprof-conv,dumpsys和adb shell am命令等,可以帮助你检查内存占用情况,并找出内存泄漏等问题。 2. 优化布局 避免使用过多的布局嵌套,尽量使用ConstraintLayout等可减少嵌套的布局,以减少内存占用。 3. 优化资源文件 对于大型的图片和其他资源文件,可以使用压缩算法减少其占用内存的大小,减少应用的内存占用。 4. 使用缓存机制 使用缓存机制可以减少从网络或磁盘中读取数据的次数,降低了内存的使用。 5. 控制加载数据的数量 为了减少内存占用,应该控制加载数据的数量。例如,在列表中,仅加载视图范围内的数据。 6. 使用分页加载 分页加载可以分多次将数据加载到内存中,而不是一次性将所有数据加载到内存中。 7. 释放不使用的资源 及时释放不使用的资源,例如:Activity中的布局文件、Bitmap等等。 8. 避免使用静态变量 静态变量可以保存状态和数据,但它们生命周期较长,在某些情况下可能需要较长时间才能释放它们的内存。因此,最好避免使用静态变量。 9. 使用BitmapFactory.Options参数 使用BitmapFactory.Options参数可以在加载大型图片时控制它们的大小和内存占用。例如,可以使用inSampleSize参数减小图片的大小。 总之,Android内存管理是复杂而重要的部分,应该重视内存优化。以上的方法只是一些参考,需要结合具体应用场景来进行优化

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值