Android 性能优化篇

Android 性能优化之内存抖动

2023-08-11  本文已影响0人  Tsm_2020

在这里先说一下在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 的思想,

上一篇下一篇

猜你喜欢

热点阅读