您的位置:首页 > 移动开发 > Android开发

Android View 内存性能分析学习 <2>

2015-12-30 10:38 507 查看
前面看了一下如何看了延时方面的分析步骤,这里在给出查看内存占用方面的,分析工具用eclipse的allocation Tracker工具.

下面盘是我做的一个测试程序:

http://pan.baidu.com/s/1gdSIi6f

主要用一个View来测试:

DurianView.java:

/**
* @Title: DurianView.java
* @Package com.durian.view
* @Description: TODO
* @author zhibao.liu from durian organization
* @date 2015-12-28 下午06:25:33
* @version V1.0
*/
package com.durian.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;

import com.durian.durianperformanceview.R;
import com.durian.utils.DurianUtils;

/**
* @ClassName: DurianView
* @Description: TODO
* @author zhibao.liu Freelancer
* @email warden_sprite@foxmail.com
* @date 2015-12-28 下午06:25:33
*
*/
public class DurianView extends View {

private final static String TAG = "DurianView";

private TypedArray mTypeArray;

private String mDurianText;
private float mDurianTextWidth;
private float mDurianTextSize;
private int mDurianLeft;
private int mDurianRight;

private int mDurianPosition;

private Paint mPaint;

private Bitmap mBitmap;

private Shader mRadialGradient = null;

private Paint mRadialPaint;

public DurianView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub

}

public DurianView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub

initView(context,attrs);

if(!isInEditMode()){
setLayerType(View.LAYER_TYPE_NONE, null);
}

}

public DurianView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

private void initView(Context context,AttributeSet attrs){

mTypeArray = context.obtainStyledAttributes(attrs,
R.styleable.durian_view);

mDurianText = mTypeArray.getString(R.styleable.durian_view_durian_text);
mDurianTextSize = mTypeArray.getInteger(
R.styleable.durian_view_durian_textsize, 16);
mDurianLeft = mTypeArray.getInteger(
R.styleable.durian_view_durian_leftpadding, 0);
mDurianRight = mTypeArray.getInteger(
R.styleable.durian_view_durian_rightpadding, 0);
mDurianPosition = mTypeArray.getInteger(
R.styleable.durian_view_durian_labelpos, 0);

mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(DurianUtils.px2sp(context, mDurianTextSize));

mDurianTextWidth = mPaint.measureText(mDurianText);

Drawable map = mTypeArray
.getDrawable(R.styleable.durian_view_durian_src);
mBitmap = DurianUtils.drawableToBitmap(map);

// 创建RadialGradient对象
// 第一个,第二个参数表示渐变圆中心坐标
// 第三个参数表示半径
// 第四个,第五个,第六个与线性渲染相同
mRadialGradient = new RadialGradient(250, 250, 100, new int[] {
Color.GREEN, Color.RED, Color.BLUE, Color.WHITE }, null,
Shader.TileMode.REPEAT);

mRadialPaint = new Paint();
mRadialPaint.setShader(mRadialGradient);

}

public void updateDraw() {
//        postInvalidate();
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);

//        canvas.clipRect(new Rect(0, 0, (int) (50 + mDurianTextWidth), 50 + 5));

canvas.drawText(mDurianText, 50, 50, mPaint);

canvas.drawLine(10.0f, 50.0f, 100.0f, 50.0f, mPaint);

//        canvas.drawBitmap(mBitmap, 0, 55, mPaint);

// canvas.drawCircle(250f, 250f, 100f, mPaint);
canvas.drawCircle(250f, 250f, 100f, mRadialPaint);

for(int i=0;i<1000;i++){
canvas.drawCircle(250f+10*i, 250f+10*i, 100f, mRadialPaint);
/*Drawable map = mTypeArray
.getDrawable(R.styleable.durian_view_durian_src);
mBitmap = DurianUtils.drawableToBitmap(map);*/
canvas.drawBitmap(mBitmap, 0+1*i, 55+1*i, mPaint);
}

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int minw = getPaddingLeft() + getPaddingRight()
+ getSuggestedMinimumWidth();
int w = resolveSizeAndState(minw, widthMeasureSpec, 1);

int minh = MeasureSpec.getSize(w) - (int) mDurianTextWidth
+ getPaddingBottom() + getPaddingTop();
int h = resolveSizeAndState(MeasureSpec.getSize(w)
- (int) mDurianTextWidth, heightMeasureSpec, 0);

setMeasuredDimension(w, h);

}

}


注意上面程序onDraw方法里面的.

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);

// canvas.clipRect(new Rect(0, 0, (int) (50 + mDurianTextWidth), 50 + 5));

canvas.drawText(mDurianText, 50, 50, mPaint);

canvas.drawLine(10.0f, 50.0f, 100.0f, 50.0f, mPaint);

// canvas.drawBitmap(mBitmap, 0, 55, mPaint);

// canvas.drawCircle(250f, 250f, 100f, mPaint);
canvas.drawCircle(250f, 250f, 100f, mRadialPaint);

for(int i=0;i<1000;i++){
canvas.drawCircle(250f+10*i, 250f+10*i, 100f, mRadialPaint);
/*Drawable map = mTypeArray
.getDrawable(R.styleable.durian_view_durian_src);
mBitmap = DurianUtils.drawableToBitmap(map);*/
canvas.drawBitmap(mBitmap, 0+1*i, 55+1*i, mPaint);
}

}
主要关注for循环里面的.

按照上面的修改,运行程序:

<1> : 让eclipse切换DDMS下:



选中自己的app进程,如上!

<2> : 然后切换右边的allocation tracker选项下:



点击"Start Tracking",然后"Get allocation" :



上面的信息,我发现每次都有,应该是一些其他方面的信息,和APP本身没有直接关系.

然后点击"stop tracking"按钮.

<3> : 下面正式开始,操作app里面的Button之前,先点起"Start tracking" , 然后点击界面的Button,启动另外一个带自定义View的Activity,然后点击"Stop Tracking" ,继续点击"Get Allocation" 即可:



下面其实还有很多信息列表.Allocation Size 是对应右边项所消耗的内存大小.

然后修改一下程序:

for(int i=0;i<10;i++){
canvas.drawCircle(250f+10*i, 250f+10*i, 100f, mRadialPaint);
Drawable map = mTypeArray
.getDrawable(R.styleable.durian_view_durian_src);
mBitmap = DurianUtils.drawableToBitmap(map);
canvas.drawBitmap(mBitmap, 0+1*i, 55+1*i, mPaint);
}
上面的循环次数需要改一下,如果还是保持1000,APP直接就会崩溃.这里暂时改成10次.



下面还有很多,内存量猛增.

下面我们增加一个过滤的条件:



就能够直观看到自己的那几个类所需要的内存,但是这个内存只是计算它创建时所消耗的,不会计算它后面update的部分.所以感觉在创建的时候增加内存消耗,他们的allocation size才会增大. onDraw方面里面不断申请内存空间,只会增加虚拟机dalvk部分不断消耗内存,增大了它的内存大小,所以:



更能够反映整个APP的内存开销情况.当然com.durian是分的更细了,方便程序定位.

在把程序修改一下:

for(int i=0;i<100;i++){
canvas.drawCircle(250f+10*i, 250f+10*i, 100f, mRadialPaint);
Drawable map = mTypeArray
.getDrawable(R.styleable.durian_view_durian_src);
mBitmap = DurianUtils.drawableToBitmap(map);
canvas.drawBitmap(mBitmap, 0+1*i, 55+1*i, mPaint);
}
直接运行程序:



直接崩溃,爆出OOM的.

通过分析上面的程序,对于OOM的定位还是非常容易的,只要掌握分析方法和思路,已经定位目标,查出导致OOM的并不是很难.


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: