程序员Android开发Android开发

Android | App内存优化 之 内存泄漏 要点概述 以及

2019-11-28  本文已影响0人  凌川江雪

本文目录:

  • 内存泄漏的定义、表现、危害、情景,及避免OOM的技巧
  • Memory Analyzer Tool(MAT)简述、下载、安装
  • 内存泄漏解决实战
  • 解决方法小结

内存泄漏的定义、表现、危害、情景,及避免OOM的技巧

定义

表现

危害

内存不足 -- GC频繁 -- OOM

可能出现、需要注意的情景

如何避免OOM?

1.Bitmap优化
Bitmap非常消耗内存,
而且在Android中,读取bitmap时,
一般分配给虚拟机的图片堆栈只有8M,所以经常造成OOM问题。
所以有必要针对Bitmap的使用作出优化:

1.1. 图片显示:加载合适尺寸的图片,比如显示缩略图的地方不要加载大图。

1.2. 图片回收:使用完bitmap,及时使用Bitmap.recycle()回收。
问题:Android不是自身具备垃圾回收机制吗?此处为何要手动回收。

Bitmap对象不是new生成的,而是通过BitmapFactory生产的。
通过源码可发现是通过调用JNI生成Bitmap对象nativeDecodeStream()等方法)。
所以,
加载bitmap到内存里包括两部分
Dalvik(ART)内存Linux kernel内存
前者被虚拟机自动回收
后者必须通过recycle()方法,
内部调用nativeRecycle()linux kernel回收

1.3. 捕获OOM异常:程序中设定如果发生OOM的应急处理方式。

1.4. 图片缓存:内存缓存、硬盘缓存等

1.5. 图片压缩:直接使用ImageView显示Bitmap时会占很多资源,
尤其当图片较大时容易发生OOM。
可以使用BitMapFactory.Options对图片进行压缩。


1.6. 图片像素(质量):android默认颜色模式为ARGB_8888, 显示质量最高,占用内存最大。
若要求不高时可采用RGB_565等模式。
还可以使用WebP
图片大小图片长度 * 宽度 * 单位像素 所占据字节数

ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存 (默认)
RGB_565:每个像素占用2byte内存

1.7. 考虑使用inBitmap图片优化之inBitmap

2. 巧用对象引用类型

3. 使用 池 pool 内存对象重复利用

a.ListView/GridView源码可以看到重用的情况ConvertView的复用。
RecyclerViewRecycler源码。
b.Bitmap的复用
Listview等要显示大量图片。
需要使用LRU缓存机制来复用图片。

4. 使用更加轻量的数据结构:
考虑适当的情况下,
使用更加高效的安卓专门为手机研发的数据结构类
ArrayMap/SparseArray/SparseLongMap/SparseIntMap/SparseBoolMap
替代HashMap等传统数据结构。
HashMap.put(string,Object);Object o = map.get(string);会导致一些没必要的自动装箱拆箱
HashMap,HashMap更耗内存,
因为它需要额外的实例对象来记录Mapping操作,
SparseArray更加高效
因为它避免了Key Value自动装箱,和装箱后解箱操作

5. StringBuilder替代String: 在有些时候,
代码中会需要使用到大量的字符串拼接的操作,
这种时候有必要考虑使用StringBuilder来替代频繁的“+”

6.避免在类似onDraw这样的方法中创建对象
因为它会迅速占用大量内存,引起频繁的GC甚至内存抖动

参考文章

Memory Analyzer Tool(MAT)简述、下载、安装

MAT安装及使用教程
文件下载下来的是一个zip压缩包,

解压压缩包,
进入到如下目录,
双击对应的exe文件,
即可开始使用:
工具初始界面如下:

内存泄漏解决实战

定义类似观察者的一个接口CallBack
以及类似被观察者的一个实现类CallBackManager:

public interface CallBack {
    void dpOperate();
}

----

public class CallBackManager {

    public static ArrayList<CallBack> sCallBacks = new ArrayList<>();

    public static void addCallBack(CallBack callBack) {
        sCallBacks.add(callBack);
    }

    public static void removeCallBack(CallBack callBack) {
        sCallBacks.remove(callBack);
    }

}

activity_memoryleak.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_memoryleak"
        android:layout_width="50dp"
        android:layout_height="50dp" />

</LinearLayout>

MemoryLeakActivity.java:

/**
 * 模拟内存泄露的Activity
 */
public class MemoryLeakActivity extends AppCompatActivity implements CallBack{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memoryleak);
        ImageView imageView = findViewById(R.id.iv_memoryleak);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
        imageView.setImageBitmap(bitmap);

        CallBackManager.addCallBack(this);
    }

    @Override
    public void dpOperate() {
        // do sth
    }
}

Android studio 进入 adb 命令 ---使用terminal 终端 进入sdk 找到 platform-tools 目录进入即可

/**
 * 模拟内存泄露的Activity
 */
public class MemoryLeakActivity extends AppCompatActivity implements CallBack{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memoryleak);
        ImageView imageView = findViewById(R.id.iv_memoryleak);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
        imageView.setImageBitmap(bitmap);

        CallBackManager.addCallBack(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        CallBackManager.removeCallBack(this);
    }

    @Override
    public void dpOperate() {
        // do sth
    }
}

解决方法小结





参考自
上一篇 下一篇

猜你喜欢

热点阅读