美文网首页Android 性能优化篇
Android 性能优化之内存抖动

Android 性能优化之内存抖动

作者: Tsm_2020 | 来源:发表于2023-08-11 02:24 被阅读0次

    在这里先说一下在android 系统中使用最广泛的防止内存抖动的一个机制 Message

    在android 系统中 Message 是使用最频繁的一个类之一了,整个系统的运行都是建立在 Message 只上的,那么为了防止频繁的创建和销毁对象,Message 又是使用的什么方式来防止内存抖动的呢

    1.对象缓存池

      public static Message obtain() {
          synchronized (sPoolSync) {
              if (sPool != null) {
                  Message m = sPool;
                  sPool = m.next;
                  m.next = null;
                  m.flags = 0; // clear in-use flag
                  sPoolSize--;
                  return m;
              }
          }
          return new Message();
      }
    
    
        void recycleUnchecked() {
          // Mark the message as in use while it remains in the recycled object pool.
          // Clear out all other details.
          flags = FLAG_IN_USE;
          what = 0;
          arg1 = 0;
          arg2 = 0;
          obj = null;
          replyTo = null;
          sendingUid = UID_NONE;
          workSourceUid = UID_NONE;
          when = 0;
          target = null;
          callback = null;
          data = null;
    
          synchronized (sPoolSync) {
              if (sPoolSize < MAX_POOL_SIZE) {
                  next = sPool;
                  sPool = this;
                  sPoolSize++;
              }
          }
      }
    

    Message 内部有一个叫做 是Message 的next 属性,用来记录下一个Message 内容,还有一个 sPool 的静态变量,用来保存当前缓存的头结点,那么这就形成了一个由无用消息组成的单链表
    由于是无用消息,我们不关心这个消息的内容,所以非常适合现在这种场景

    适用场景
    在循环中创建重复的对象 , 在onDraw 中组装绘制对象 , ,生产消费模式也比较使用这种情况
    下面我们句一个小例子来看一下profiler 中创建了多少个对象

    class MainActivity : AppCompatActivity() {
      private var  isRunning=false
      private val queue: LinkedBlockingQueue<TsmMessage> = LinkedBlockingQueue<TsmMessage>()
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
          findViewById<View>(R.id.tv_click).setOnClickListener {
              isRunning=true
              test()
          }
          findViewById<View>(R.id.tv_end).setOnClickListener {
              isRunning=false
          }
      }
      fun test(){
          thread {
              while (isRunning){
                  kotlin.runCatching {
                      queue.add(TsmMessage())
                      sleep(2)
                  }
              }
          }
          thread {
    
              while (isRunning){
                  kotlin.runCatching {
                      queue.take()
                    sleep(2)
                  }
              }
          }
      }
    }
    

    在这4秒多的时间里面我们一共创建了9872 个 TsmMessage 的对象


    点击一个TsmMessage 可以看到 这个对象的创建和运行的位置,kotlin 有点不准确,但是足够用了


    再来看一下我们优化后的效果


    从这里我们可以看到 在这个时间段里面,他只创建了12个对象,大大减少了我们创建对象的个数

    在项目中比较常见的 String+="abc"

    相信绝大多数人在看了这段代码都知道 string + "abc" 都知道jvm 会为我们创建重复的对象 ,如果这句话写在了 循环中 也会造成内存抖动

    对于数组 byte[] 数组的回收 Glide Array数据回收机制 LruArrayPool

    这个类的路径是 package com.bumptech.glide.load.engine.bitmap_recycle; LruArrayPool

    先来说一下他这个类的思想

    先来说一下他的put 方法,比较简单
    用这个数据的lenght 作为key 放入到map 中, 之后将这个lenght 的数据个数放入到treemap 中,整体的逻辑就是这样的

    再来说一下他的get 方法,思想特别神奇,
    入参是 length ,他的意思是我要获取一个length 的Array 数据,他会先去treemap 中获取一个等于或者大于length 最接近这个长度的数组key,再根据这个key去map中拿到一个链表中的数据,最后将treemap 的length 的数据个数-1,整个过程完成

    他的非常重要的思想就是你想获取一个长度为length 的 array ,我返回给你一个大于或者等于这个length 的array ,满足你的需求

    对于数组的回收 Glide Array数据回收机制 LruArrayPool 弊端

    再来说一下这个方法的弊端

    private final Map<Class<?>, NavigableMap<Integer, Integer>> sortedSizes = new HashMap<>();
    

    弄了一个简易的测试方法发现,在使用Interger 做了Map 的key ,但是我们实际传入的是int 类型,在get 与 put 的过程中 jvm 就会自动实现 对象拆箱装箱的这个操作,也创建了非常多的对象,那么如何去优化他呢, int 作为key 的 Array ,没错 就是SparseArray 的思想,

    相关文章

      网友评论

        本文标题:Android 性能优化之内存抖动

        本文链接:https://www.haomeiwen.com/subject/jibzpdtx.html