安卓内存-UI流畅度

安卓性能Performance

Android性能

  1. 内存
  2. UI流畅度

================================
数据体现

  1. 内存 ( 占用多少 泄露多少)
  2. UI流畅度度 每秒帧数 响应时间
  3. IO 阻塞式响应时间

================================

安卓内存紧张引起问题

  1. OOM (Out Of Memory) 引起GC
  2. UI不流畅
  3. …….

Android内存紧张引起的原因:

  1. 单例模式下static数据
  2. 多线程进程周期过长 导致占有的资源迟迟不能回收
  3. 大胖子 bitmap
  4. Cursor 索引

解决:

  1. 及时销毁不使用对象
  2. bitmap可设置缩放比例
  3. SoftReference 软引用
  4. Cursor及时关闭

================================
Android内存情况工具

  1. DDMS ( HEAP堆 Allocation Tracker内存分配情况)
    这里写图片描述

这里写图片描述

  1. MAT Momery Analyzer( Leak Suspect 内存泄露报告) (Top Components吃货报告) (Histogram Class占用内存) (Dominator tree 占用内存较多对象 Hold了什么导致不能释放)
  2. android.os.Debug (自有API)
    这里写图片描述

这里写图片描述

================================
安卓UI卡顿原因:
这里写图片描述

================================
垂直同步
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

http://www.jianshu.com/p/838835d21ea6

测评:对系统进行大量有针对性的测试,以得到合适的测试数据。
分析系统瓶颈:分析测试数据,找到其中的hotspot(热点,即bottleneck 瓶颈)。
性能优化:对hotspot相关的代码进行优化

Traceview简介
Traceview是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot。
Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。
Traceview打点
Debug.startMethodTracing(String tracePath);
Debug.stopMethodTracing();

Systrace 打点
python systrace.py –time=10 -o mynewtrace.html -a[your-app-package-name] sched gfx view wm
Trace.beginSection(“tag”);
Trace.endSection;

================================

        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        int mMemery = am.getMemoryClass(); // 以M为单位  一般256M 大于该大小 程序会崩溃
        int mLagerMemery = am.getLargeMemoryClass(); // 以M为单位  一般256M 大于该大小 程序会崩溃

        float totalMomery = Runtime.getRuntime().totalMemory() * 1.0f /( 1024 * 1024 );
        float freeMomery = Runtime.getRuntime().freeMemory() * 1.0f /( 1024 * 1024 );
        float maxMomery = Runtime.getRuntime().maxMemory() * 1.0f /( 1024 * 1024 );

        adb shell dumpsys meminfo surfaceflinger  命令查看进程内存情况
        adb shell dumpsys meminfo com.xxx.xxx.xxx 查看进程内存情况

这里写图片描述

这里写图片描述
这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

这里写图片描述


【频繁字符串拼接使用 StringBuffer】
package test;
import java.util.Random;

public class A {
   int row = 30;
   int length = 1000 ; 
   int[][] intArray = new int[row][length];

   public A() {
       begin();
       showString();
       showStringBuffer();
}
    public static void main(String[] args) {
        A a =new A();
    }



    private void showString() {
        String str = "";
        long time1 = System.currentTimeMillis();
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < length; j++) {
                str = str + intArray[i][j] ;
            }
        }
        long time2 = System.currentTimeMillis();
        System.out.println("String拼接运行了"+(time2-time1)/1000.0 + "秒");
    }


    private void showStringBuffer() {
        StringBuffer str = new StringBuffer();
        long time1 = System.currentTimeMillis();

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < length; j++) {
                str = str.append(intArray[i][j]+"");
            }
        }
        long time2 = System.currentTimeMillis();
        System.out.println("StringBuffer 拼接运行了"+(time2-time1)/1000.0 + "秒");
    }




    private void begin() {
        Random ran = new Random();
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < length; j++) {
                intArray[i][j] = ran.nextInt(10000);
            }
        }

    }
}

输出: 
String拼接运行了1.226秒
StringBuffer 拼接运行了0.009

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

package com.example.testa;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.ArrayMap;

/**
 * 通过软引用管理多张图片的方法
 * 
 * 
 */
@SuppressLint("NewApi")
public class BitmapCache {

    static private BitmapCache cache;

    // 每次取bitmap 先查看该bitmap对应的string标志是否在该MAP中
    // 如果不在 说明被释放掉了 或者第一次加载
    private ArrayMap<String, MySoftRef> hashRefArayMap;

    // 垃圾引用的队列 所引用的对象已被收回 则将该引用加入该队列
    private ReferenceQueue<Bitmap> queue;

    // 继承 SoftReference 使得每一个引用都有唯一的标识
    private class MySoftRef extends SoftReference<Bitmap> {
        private String key = "";

        public MySoftRef(Bitmap bitmap, ReferenceQueue<Bitmap> queue, String str) {
            super(bitmap, queue);
                        //SoftReference(Bitmap , ReferenceQueue<Bitmap>) 原始构造器 
            //bitmap的软引用被回收,会出现在队列ReferenceQueue中 ,ReferenceQueue 保存了被回收的引用
            key = str;
        }
    }

    @SuppressLint("NewApi")
    private BitmapCache() {
        hashRefArayMap = new ArrayMap<String, MySoftRef>();
        queue = new ReferenceQueue<Bitmap>();
    }

    static public BitmapCache getInstance() {
        if (cache == null) {
            cache = new BitmapCache();
        }
        return cache;
    }

    // 以软引用的方式对Bitmap对象的实例进行引用 并保存该引用
    public void addCacheBitmap(Bitmap bmp, String key) {
        cleanCache(); // 清除垃圾引用 
        MySoftRef ref = new MySoftRef(bmp, queue, key);
        hashRefArayMap.put(key, ref);
    }




    /**
     * 依据所指定的drawable下资源ID (后者SD卡路径 网络路径),获取到bitmap对象的实例
     */

    public Bitmap getBitmap(String  resId) {
        Bitmap bitmap = null;
        try {
            if(hashRefArayMap.containsKey(resId)){
                MySoftRef ref = (MySoftRef) hashRefArayMap.get(resId);
                bitmap = (Bitmap) ref.get();
                if(bitmap != null)
                return bitmap;
            }
        } catch (Exception e) {
            return null;
        }
     // 如果没有软引用,或者索引的实例为 null ,需要重新创建实例
    //   bitmap =  BitmapFactory.decodeFile(resId);
    //   hashRefArayMap.put(resId, new MySoftRef(bitmap, queue, resId));


         return bitmap;
    }


    private void cleanCache() {  // 移除已经被回收的软引用 使得 hashRefArayMap正常
        MySoftRef ref = null;
        // 系统清除软引用 会把回收的东西放到 队列里  queue.poll()
        /*在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。
         * 如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。
         * 利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。
         * 于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉
         * */
        while ((ref = (MySoftRef) queue.poll()) != null){  // 队列里的软引用不为空 那么说明这个引用被回收了
            hashRefArayMap.remove(ref.key);
        }
    }


    public void clearCache() { //  清除 BitmapCache 全部数据
        cleanCache();
        hashRefArayMap.clear();
        System.gc();
        System.runFinalization();
    }

}

======================================

package com.example.testa;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import android.graphics.Bitmap;

//使用LRU算法, 比BitmapCache能达到更好的回收控制,BitmapCache无法保证当前取到的Bitmap为空 是随机的 
// LRU算法能实现  最不常用的那个Bitmap能 首先被回收掉
// 使用LRU 算法 实现 Bitmap的缓存
public class MemoryCache {
    private static final String TAG = "MemoryCache";

    // true 表示 使用LRU算法 进行排序 8 表示当前最大容量 0.75表示容量因子 当容量大于75% 时,容量曾倍 最大容量变为16
    // 这个LinkedHashMap容器为线程不安全的 所在在外面套一个 synchronizedMap 使得线程安全
    private Map<String, Bitmap> cache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(8, 0.75f, true));

    private long size = 0; // 保存当前Map中已经保存了的字节数
    private long limit = 1000000; // Max byte 容器最大字节

    public void MemoryCache() {
        // TODO Auto-generated constructor stub
        setLimit(Runtime.getRuntime().maxMemory() / 4);
    }

    public void setLimit(long mLimit) {
        // TODO Auto-generated constructor stub
        limit = mLimit;
        // 最大缓存设置为 mLimit / (1024*1024) MB 大小
    }

    public Bitmap get(String id) {
        try {
            if (!cache.containsKey(id))
                return null;
            return cache.get(id);
        } catch (Exception e) {
            return null;
        }
    }

    public void put(String id, Bitmap bitmap) {
        try {
            if (cache.containsKey(id)) // 检查图片是否存在 如果有的话 可能是更新 那么更新大小
                size -= getSizeInBytes(cache.get(id));
            cache.put(id, bitmap);
            size += getSizeInBytes(cache.get(id));
            checkSize();
        } catch (Exception e) {

        }
    }

    public void clear() {
        cache.clear();
    }

    private long getSizeInBytes(Bitmap bitmap) {
        if (bitmap == null) {

            return 0;
        }
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    private void checkSize() { // 确保 每次size 都小于 limit
        // 迭代的原则是 从最近最少用的那个对象开始迭代
        if (size > limit) {
            Iterator<Map.Entry<String, Bitmap>> iter = cache.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, Bitmap> entry = iter.next();
                size -= getSizeInBytes(entry.getValue());
                iter.remove(); // 在MAP中最少用的那个Bitmap就被释放掉了
                if (size <= limit)
                    break;
            }
        }
    }

}
发布了71 篇原创文章 · 获赞 36 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章