安卓內存-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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章