内存优化:内存抖动和内存泄漏
Posted 斯音
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存优化:内存抖动和内存泄漏相关的知识,希望对你有一定的参考价值。
LMK;内存抖动、内存泄漏与内存溢出
优化的结果:使得app流畅不卡
内存抖动
短时间内有大量对象创建与销毁,它伴随着频繁的GC。
比较典型的就是字符串的拼接造成内存抖动。
比如:
String str = "";
for(int i=0; i< 10; i++)
str += i;
+=操作会编译成StringBuilder对象,然后调用StringBuilder的append方法进行拼接。
所以上述代码会创建10个StringBuilder对象,每执行一次+操作都会新创建一个StringBuilder对象。
优化方法:避免使用+或者+=操作,使用StringBuilder来实现字符串的拼接
StringBuilder str = new StringBuilder();
for (int i = 0; i < 10; i++)
str.append(i);
内存抖动实战
一个不断旋转的试图,优化前的代码:
public class iosStyleLoadingView1 extends View
private final Context context;
private double radius;
private double insideRadius;
private float northwestXStart;
private float northwestYStart;
private float northXStart;
private float northYStart;
private float notheastXStart;
private float notheastYStart;
private float eastXStart;
private float eastYStart;
private float southeastXStart;
private float southeastYStart;
private float southXStart;
private float southYStart;
private float southwestXStart;
private float southwestYStart;
private float westXStart;
private float westYStart;
private float northwestXEnd;
private float northwestYEnd;
private float northXEnd;
private float northYEnd;
private float notheastXEnd;
private float notheastYEnd;
private float eastXEnd;
private float eastYEnd;
private float southeastXEnd;
private float southeastYEnd;
private float southXEnd;
private float southYEnd;
private float southwestXEnd;
private float southwestYEnd;
private float westXEnd;
private float westYEnd;
private int currentColor = 7;
String color[] = new String[]
"#a5a5a5",
"#b7b7b7",
"#c0c0c0",
"#c9c9c9",
"#d2d2d2",
"#dbdbdb",
"#e4e4e4",
"#e4e4e4"
;
public IOSStyleLoadingView1(Context context)
this(context,null,0);
public IOSStyleLoadingView1(Context context, AttributeSet attrs)
this(context,null,0);
public IOSStyleLoadingView1(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this.context = context;
radius = UIKits.dip2Px(context, 9);
insideRadius = UIKits.dip2Px(context, 5);
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(UIKits.dip2Px(context, 2));
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
Path p0 = new Path();
paint.setColor(Color.parseColor(color[0]));//Color.parseColor方法会调用String的substring()方法,substring()方法会产生新的String对象
p0.moveTo(northwestXStart, northwestYStart);
p0.lineTo(northwestXEnd, northwestYEnd);
canvas.drawPath(p0, paint);
Path p1 = new Path();
paint.setColor(Color.parseColor(color[1]));
p1.moveTo(northXStart, northYStart);
p1.lineTo(northXEnd, northYEnd);
canvas.drawPath(p1, paint);
Path p2 = new Path();
paint.setColor(Color.parseColor(color[2]));
p2.moveTo(notheastXStart, notheastYStart);
p2.lineTo(notheastXEnd, notheastYEnd);
canvas.drawPath(p2, paint);
Path p3 = new Path();
paint.setColor(Color.parseColor(color[3]));
p3.moveTo(eastXStart, eastYStart);
p3.lineTo(eastXEnd, eastYEnd);
canvas.drawPath(p3, paint);
Path p4 = new Path();
paint.setColor(Color.parseColor(color[4]));
p4.moveTo(southeastXStart, southeastYStart);
p4.lineTo(southeastXEnd, southeastYEnd);
canvas.drawPath(p4, paint);
Path p5 = new Path();
paint.setColor(Color.parseColor(color[5]));
p5.moveTo(southXStart, southYStart);
p5.lineTo(southXEnd, southYEnd);
canvas.drawPath(p5, paint);
Path p6 = new Path();
paint.setColor(Color.parseColor(color[6]));
p6.moveTo(southwestXStart, southwestYStart);
p6.lineTo(southwestXEnd, southwestYEnd);
canvas.drawPath(p6, paint);
Path p7 = new Path();
paint.setColor(Color.parseColor(color[7]));
p7.moveTo(westXStart, westYStart);
p7.lineTo(westXEnd, westYEnd);
canvas.drawPath(p7, paint);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
double centerX = getMeasuredWidth() / 2;
double centerY = getMeasuredHeight() / 2;
double leg = radius * Math.cos(Math.PI / 4);
double insideLeg = insideRadius * Math.cos(Math.PI / 4);
northwestXStart = (float) (centerX - leg);
northwestYStart = (float) (centerY - leg);
northXStart = (float) centerX;
northYStart = (float) (centerY - radius);
notheastXStart = (float) (centerX + leg);
notheastYStart = (float) (centerY - leg);
eastXStart = (float) (centerX + radius);
eastYStart = (float) centerY;
southeastXStart = (float) (centerX + leg);
southeastYStart = (float) (centerY + leg);
southXStart = (float) centerX;
southYStart = (float) (centerY + radius);
southwestXStart = (float) (centerX - leg);
southwestYStart = (float) (centerY + leg);
westXStart = (float) (centerX - radius);
westYStart = (float) centerY;
northwestXEnd = (float) (centerX - insideLeg);
northwestYEnd = (float) (centerY - insideLeg);
northXEnd = (float) centerX;
northYEnd = (float) (centerY - insideRadius);
notheastXEnd = (float) (centerX + insideLeg);
notheastYEnd = (float) (centerY - insideLeg);
eastXEnd = (float) (centerX + insideRadius);
eastYEnd = (float) centerY;
southeastXEnd = (float) (centerX + insideLeg);
southeastYEnd = (float) (centerY + insideLeg);
southXEnd = (float) centerX;
southYEnd = (float) (centerY + insideRadius);
southwestXEnd = (float) (centerX - insideLeg);
southwestYEnd = (float) (centerY + insideLeg);
westXEnd = (float) (centerX - insideRadius);
westYEnd = (float) centerY;
@Override
protected void onAttachedToWindow()
super.onAttachedToWindow();
startAnimation();
private ValueAnimator valueAnimator;
public void startAnimation()
valueAnimator = ValueAnimator.ofInt(7, 0);
valueAnimator.setDuration(400);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@Override
public void onAnimationUpdate(ValueAnimator animation)
if ((int) animation.getAnimatedValue() != currentColor)
String b[] = new String[color.length];//移动后的数组
for (int c = 0, size = color.length - 1; c < size; c++)
b[c + 1] = color[c];
b[0] = color[color.length - 1];
color = b;
invalidate();
currentColor = (int) animation.getAnimatedValue();
);
valueAnimator.start();
利用android Studio内置的Profiler工具查看内存使用情况:
可以看到内存产生抖动,并且随着程序的运行,内存一直在增加,选择一段时间分析内存中的对象:
可以看到内存中的有大量的Path对象和String对象,一般来说是有异常的,分析代码看看是否能避免这种情况。
可以在onDraw方法里进行优化,优化后的代码:
/**
* 优化后的IOSStyleLoadingView
* onDraw方法里不创建Path和Paint对象,不调用Color.parseColor创建String对象
*
*/
public class IOSStyleLoadingView extends View
private final Context context;
private double radius;
private double insideRadius;
private float northwestXStart;
private float northwestYStart;
private float northXStart;
private float northYStart;
private float notheastXStart;
private float notheastYStart;
private float eastXStart;
private float eastYStart;
private float southeastXStart;
private float southeastYStart;
private float southXStart;
private float southYStart;
private float southwestXStart;
private float southwestYStart;
private float westXStart;
private float westYStart;
private float northwestXEnd;
private float northwestYEnd;
private float northXEnd;
private float northYEnd;
private float notheastXEnd;
private float notheastYEnd;
private float eastXEnd;
private float eastYEnd;
private float southeastXEnd;
private float southeastYEnd;
private float southXEnd;
private float southYEnd;
private float southwestXEnd;
private float southwestYEnd;
private float westXEnd;
private float westYEnd;
private int currentColor = 7;
String color[] = new String[]
"#a5a5a5",
"#b7b7b7",
"#c0c0c0",
"#c9c9c9",
"#d2d2d2",
"#dbdbdb",
"#e4e4e4",
"#e4e4e4"
;
int[] colors = new int[8];
public IOSStyleLoadingView(Context context)
this(context, null, 0);
public IOSStyleLoadingView(Context context, AttributeSet attrs)
this(context, null, 0);
/**
* 提前在构造方法里调用Color.parseColor解析好数据,而不是在onDraw方法里频繁调用
*
*
* @param context
* @param attrs
* @param defStyleAttr
*/
public IOSStyleLoadingView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this.context = context;
radius = UIKits.dip2Px(context, 9);
insideRadius = UIKits.dip2Px(context, 5);
for (int i = 0; i < color.length; i++)
colors[i] = Color.parseColor(color[i]);
paint.setAntiAlias(true);
paint.setStrokeWidth(UIKits.dip2Px(context, 2));
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
Path path = new Path();
Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
path.reset();
paint.setColor(colors[(currentColor++) % 8]);
path.moveTo(northwestXStart, northwestYStart);
path.lineTo(northwestXEnd, northwestYEnd);
canvas.drawPath(path, paint);
path.reset();
paint.setColor(colors[(currentColor++) % 8]);
path.moveTo(northXStart, northYStart);
path.lineTo(northXEnd, northYEnd);
canvas.drawPath(path, paint);
path.reset();
paint.setColor(colors[(currentColor++) % 8]);
path.moveToAndroid 性能优化--内存优化--(内存优化工具内存管理机制内存抖动内存泄漏)
Android 性能优化--内存优化--(内存优化工具内存管理机制内存抖动内存泄漏)