内存性能

共享内存

保存所有的App都会使用到的公共框架类、资源以及本地类库资源。

代表:Zygote

zygote受精卵的意思,可以分裂出很多细胞出来。
在Android里,Zygote是个进程,该进程中包含了所有的框架类,共用的资源,以及预加载的本地库。

私有内存

只能被你的App使用,而其他App不能使用的内存。

脏内存

数据仅仅存在于RAM中,一旦被清理,只能重新通过跑APP才能拿到数据。

干净内存

数据不仅在RAM中,而且还保存在disk上,一旦被清理,再读取一下disk就好了。

垃圾回收

一旦某个对象在APP中没有一个活动的引用。
注意,是活动的引用,我的理解是,引用它的对象是活动的,不是死的,如果两个死的引用互相引用,他们依旧会被回收掉。垃圾回收会先从根部的对象开始(知道这些对象是活动的并且正被进程所使用),并且沿着每个引用去查找它们的关联。如果一个对象不在这个有效引用的列表中,那么它肯定是不会再使用了,就可以被回收。此时,分配给这个对象的内存空间也可以回收了

这里写图片描述

GC在Android上的演进

在Gingerbread之前的版本,设备内存很小,所以App往往有较小的堆。垃圾收集器是一个“中断一切”的收集器,在垃圾收集的过程中,它会使所有CPU的进程和线程都停止。GC是中央集权制的。

在Gingerbread版本中,建立了一个并发的GC来做局部的回收工作。并发GC会和你的App一起运行,而不是阻止App运行。GC权利自治了。

在KitKat或者更早的版本运行的设备,内存回收,简单的进行 标记 及 清除 机制,这留下大量的碎片化自由内存,虽然总量很大,但是因为不是连续的,所以在申请超过最大自由内存碎片的体积时,就容易出现内存泄漏。
这里写图片描述

在Lollipop版本,Android运行时由Dalvik转变为ART,垃圾回收的效率又一次被提高了。在ART中,大型的对象(像是图片)有它们自己特殊的堆,这些堆是专门用于简化大型对象的内存管理用的(是这些大型对象的加速GC)。
ART垃圾回收算法:当一个App不在前台的时候,它将是一个Semi-Space的GC。因为App不在前台运行,重写在内存中的对象是安全的。过程是先将用到的内存数据逐块拷贝到一块新的内存区域,看第二行,这时内存是连续的。然后将这一大块连续的内存数据拷贝会然来的位置。这样碎片化自由内存被腾空了,注意,此时APP是被挂起的.
这里写图片描述

内存使用

在一个设备上可以用到多少内存?ActivityManager.getMemoryClass将会返回App可以使用的堆的最大值。如果它显示的比理想的要小,你可以减少显示内容,又或者将图片转换为较小的格式。如果你的App是内存密集型的,可以请求getLargeMemoryClass()来获得更多内存,但是必须慎重使用它,因为在垃圾回收事件中,大的内存堆将会降低App的速度(因为此架构不得不通过查找更多的数据去捕获无用的对象)。

内存使用状况报告

adb shell dumpsys meminfo

这里写图片描述

What’s PSS

Proportional Set Size (PSS)
PSS 就是app所使用的全部内存。而 全部内存=私有内存 + 部分共享内存
该报告将整个内存的使用按照类型做了分类,

我想具体的了解某个app的内存使用情况。加上PID

adb shell dumpsys meminfo 1389

这里写图片描述

主要看几点:
* PSS Total
the total memory in use by the app (recall PSS = shared + private memory)
* the private dirty memory (memory only in use by the app, and not stored on disk).
可以看到大部分都是私有脏数据。

Objects表格统计了视图数量,资源数量,以及acitvity的数量。

Procstats

如何开启

设置 >> 开发者选项 >> 进程统计

可以通过Stats type来切换要看的统计类型。
这里写图片描述
有这么几种类型:
这里写图片描述

the cached memory 到底是个啥?

如何看呢?

这里写图片描述
上面的大条,是表明内存的总占用量,会有绿色,黄色,红色,表明内存使用正常程度。
下面罗列了每个应用,那么小条表明单个应用所占用的比率,而后面的百分比可不是内存占用量,其=占用内存的时间/统计的总时长。比如上面美团的push进程在统计的4小时9分的96%的时间里一致使用着系统内存。

命令方式

adb shell dumpsys procstats com.sankuai.mtmp.push

这里写图片描述

格式(总内存:低水平-平均水平-高水平/私有内存:低水平-平均水平-高水平):
TOP 前台运行进程
SOff 屏幕关闭 SOn开启

Android内存警告

上面提到procstats命令可以输出内存使用报告,但是app在运行过程中会一直监控着该报告,然后通过onTrimMemory来通知你app的内存使用状态。
TRIM_MEMORY_RUNNING_MODERATE
This is your first warning.
TRIM_MEMORY_RUNNING_LOW
This is like the yellow light. It is your second warning to begin to trim resources to improve performance.
TRIM_MEMORY_RUNNING_CRITICAL
This is the red light. If you keep on executing without clearing up memory resource, the system is going to begin killing background processes to get more memory for you,系统会为了你app(前台)来杀死点后台进程来腾点空间. Unfortunately, that will lower your app’s performance.(因为GC可能会造成jank)
TRIM_MEMORY_UI_HIDDEN
Your app was just moved off the screen, so this is a good time to release large UI resources. Now your app is on the list of cached apps. If there are memory problems, your process may be killed. Being a background app, release as much as you can so that your app can resume faster than a pure restart. There are three levels:
TRIM_MEMORY_BACKGROUND
Your app is on the list, but near the end.
TRIM_MEMORY_MODERATE
Your app is in the middle of the kill list.
TRIM_MEMORY_COMPLETE
This is the “your app is next to be killed” warning.

内存泄漏

Heap Dump

如何进入

这里写图片描述

如何看

这里写图片描述

通过下图能看出空闲空间的碎片化程度,这里空闲空间是由467块碎片组成,最大碎片 120KB,最小碎片16B,中等碎片为96B。
这里写图片描述

总结

Heap dump工具将内存的使用根据类型分类,如果想要查找内存问题,就需要Allocation Tracker

Allocation Tracker 分配追踪器

如何用

这里写图片描述
按下Start Tracking按钮来收集分配的列表。执行测试,然后点击Get Allocations
注意:
* get alloctions是累加的,重新测试的话就应该从stop tracking再开始。

它能做啥

它能定位到申请了多少内存,并且是谁申请的,根据谁申请的来判断是否这次申请是有必要的。
还有些功能:
* 可以按每列内容排序
* 可以过滤,比如我只对某个Activity感兴趣。
* Allocation Size的单位是B.

如何用它来查找内存问题呢?

我在测试当中故意制造了一些内存泄漏,在onCreate的时候会申请2M内存添加到另外一个类的静态成员队列中。那么每当旋转屏幕的时候,每次都会去申请2M内存。
启动应用,点击start ,旋转两次屏幕,点击get,结果如下:
这里写图片描述

我们能看出什么呢?
* 按道理说,启动应用一次,旋转两次屏幕,应该申请了3次,但是只显示了2次,这说明这个记录是从点击start到get的中间过程的内存申请记录,并不包含start之前记录。
* 如果在记录的过程中,有相同的内存是频繁的被申请(包括大体积),那么就得关注一下了。
* 测试过程中应该多操作一下,而不是静默着,比如旋转屏幕啊,多点点关关,或者回到后台再返回前台等。

更深层次的栈分析器:MAT LeakCanary

Eclipse Memory Analysis Tool (MAT)

这里写图片描述
生成文件。然后利用MAT打开
android studio 里缺省没有,得去http://www.eclipse.org/mat/downloads.php下载。

如何找到内存问题

Shallow Heap 是对象所用的内存
Retained Heap 是对象加上所有对象引用的对象的内存

首先内存问题的本质是什么
GC 会从Root引用开始遍历,然后将哪些没有被引用到的”无主野狗“给回收掉。
有一种情况就是,有些已经没有用的内存却被持久的引用着使得一直无法释放。比如 类静态成员引用一大块内存。这个持久的引用就像辛德勒,他利用自己的合法证件及特权将大批的犹太人保护起来,不让纳粹抓走犹太人,也许有很多像辛德勒这样的,对于纳粹高层来说,为了找到被”非法保护“的犹太人,就要先揪出辛德勒

这里写图片描述

Reports:Leak Suspects

可以自己生成内存泄漏的分析报告
这里写图片描述
可以看到耗用8个字节的引用iceberg

Histogram

这里写图片描述
通常需要关注2类:
* Shallow Heap较小,Retained Heap较大
* Shallow Heap较大,Retained Heap也较大

碰到问题Unknown HPROF Version (JAVA PROFILE 1.0.3)

The hprof file you get from Android has android specific format. You should convert hprof file take from Android OS into standard hprof format.For this you can use hprof-conv tool that is located at AndrodiSDK/tools/hprof-conv.
For example:
hprof-conv android.hprof mat.hprof
android 导出的是android格式的hprof格式,但是这个并不是通用格式,所以需要利用工具转化一下。

LeakCanary

2015 square公司发布,比MAT使用更简单

在build.gradle文件上添加两个依赖:

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
//LeakCanary reference watcher
public static RefWatcher getRefWatcher(Context context) {
    AmiAGoat application = (AmiAGoat) context.getApplicationContext(); 
    return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() { 
    super.onCreate();
    //on app creation - turn on leakcanary
    refWatcher = LeakCanary.install(this); 
}

然后给CancelTheWatch类和Iceberg类添加了特定的引用watchers:

//LeakCanary watching the variables
RefWatcher wishTheyHadAWatch = AmiAGoat.getRefWatcher(this);    wishTheyHadAWatch.watch(NoNeed);
RefWatcher icebergWatch = AmiAGoat.getRefWatcher(this);     icebergWatch.watch(theBigOne);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值