安卓性能Performance
Android性能
- 内存
- UI流畅度
================================
数据体现
- 内存 ( 占用多少 泄露多少)
- UI流畅度度 每秒帧数 响应时间
- IO 阻塞式响应时间
================================
安卓内存紧张引起问题
- OOM (Out Of Memory) 引起GC
- UI不流畅
- …….
Android内存紧张引起的原因:
- 单例模式下static数据
- 多线程进程周期过长 导致占有的资源迟迟不能回收
- 大胖子 bitmap
- Cursor 索引
解决:
- 及时销毁不使用对象
- bitmap可设置缩放比例
- SoftReference 软引用
- Cursor及时关闭
================================
Android内存情况工具
- DDMS ( HEAP堆 Allocation Tracker内存分配情况)
- MAT Momery Analyzer( Leak Suspect 内存泄露报告) (Top Components吃货报告) (Histogram Class占用内存) (Dominator tree 占用内存较多对象 Hold了什么导致不能释放)
- 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;
}
}
}
}