1、进程指标
us用户空间占百分比
sy内核空间占百分比
ni用户进程空间内该百年过优先级的进程占用CPU百分比
id cpu空闲百分比
wa 等待输入输出的CPU的时间的百分比
hi 硬中断
si软中断
ir 中断
2、内存哪里去了
- MemTotal: 2042260 kB
- MemFree: 170764kB
- MemAvailable: 587648 kB
- Buffers: 14256kB
- Cached: 570504 kB
- Memtotal 除了boot 内核 内存,剩下可供系统使用的内存
- Memfree 未被使用的内存
- MemAvailable 统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以MemFree不能代表全部可用的内存,这部分可回收的内存加上MemFree才是系统可用的内存,即:MemAvailable≈MemFree+Buffers+Cached,它是内核使用特定的算法计算出来的,是一个估计值。它与MemFree的关键区别点在于,MemFree是说的系统层面,MemAvailable是说的应用程序层面
MemAvailable≈MemFree+Buffers+Cached
3、常用工具
- mat
- profile
4、LeakCanary
- 原理看我的这篇文章LeakCanary的实现原理 - 掘金 (juejin.cn)
- 分析时容易oom
- 只对activity、fragment进行预设埋点,需要自己定制源码,针对对象进行裁剪
- 不全加载到内存中,只适合线下监控
5、线上内存检测方案的思路
- leakcanary或者matrix,在线下监控。
- 使用koom,fork dump,不影响主进程的运行。
- 自带的 memory monitor进行内存监控
- 用MAT分析内存泄漏问题。
- 对activity泄漏,gc后进行dump hprof操作。
- hprof文件导入到 MAT查看activity的 引用链条。找出静态成员 或者长生命周期引用。
- 对于Bitmap,Hprof导入到Android Monitor,就可以找出来。
6、activity在执⾏销毁的时候 我们如何得知?
- 第一种lifecyclecallback。手动触发GC,会造成用户卡顿
- 第二种就是
阈值处理,达到标杆才触发GC,可以用count计数,这里细节可以再补充koom就在这里做。
7、如何判断⼀个Activity⽆法被GC机制回收?
- 用弱引用处理,referencequeue(
后续上代码)
8、内存泄漏的常用原因
- 静态变量或单例持
- 内部类 匿名内部类 持有外部内引用
- 动画在activity 销毁时 没cancel
- IO Cursor File没有close
9、koom 简单描述
-
native heap 内存泄漏监控,主要借助了 tracing garbage collection ,G1算法,解决堆内存检测的一种方案(
”可以细化“)。 -
使用之后放到项目中,
可把指标放到项目中
9.1、怎么去检测native层的内存泄漏呢?
- 第一种 自己去做 hook,很难。
- 第二种 ,libmemunreachable+xhook
- -xhook去hook malloc/free等方法,记录native内存分配元数据
-
- libmemunreachable去周期性使用mark-and-sweep获取不可达内存块信息
通过不可达内存块信息&元数据分配堆栈信息,可得泄漏数据信息.
9.2 koom总结
1、要知道libmemunreachable这个概念
2、要知道 koom如何做内存native的检测
3、方案一定要懂
4、频繁GC会导致用户可感知的卡顿。koom采用了无性能损耗的内存阈值监控。要引导面试官。
泄漏可能性达到90%。再来触发GC,提高性能。
10、内存检测思路
内存检测2种思路。
- 思路一: 利用弱引用的特性,如leakcanary/Matrix。当Activity对象编程弱可达时(没有强引用了),弱应用会被加入到引用队列中。Activity.onDestory后连续触发两次 GC,并检测引用队列,则可以 判定Activity是否发生了泄漏。但是频繁GC会造成用户可感知的卡顿。所以有第二种方法。
- 思路二: 阈值检测的方法。如koom,通过无性能损耗的内存阈值监控来触发镜像采集,这个进行采集就是fork子进程来dump。
11、dump Hprof
adb shell am dumphead
dump 会有个scopesuspendall方法来暂停所有的线程,导出hprof会很卡,而且文件很大。这对用户来说,不友好。
于是用fork子进程去dumpHprofData,fork采用 了copyonwrite的机制,原本父子享用同空间,但是如果写入则拷贝分配独立空间,也就拥有了父进程的副本,再执行dumpHprofData方法,父进程正常,不受影响。
12、动态链接库
- 核心知识点-》了解动态链接库的打开和关闭
- koom中dump会用到动态链接库,也就是jni中c调so的函数。具体学习可以看下链接 linux.die.net/man/3/dlope…
13、Profile剪裁问题
- 读取Hprof文件
- 记录Bitmap和String类信息(
why) - 移除Bitmap buffer和String value之外的基础类型数组
- 将同意张照片的Bitmap bugger指向同一个 buffer id,移除重复的Bitmap buffer
- 将数据原封不动地输出到新文件中。
14、Matrix
- Matrix的内存泄漏监控是由ResourceCanary实现的
- 准确说ResouceCanary是检测Activity内存泄漏的
- 但activtiy内存泄漏是可以dump一个堆转储文件,通过文件可以分析是否存在相同的Bitmap。
- ResourceCanary,通过WeakReference特性和haha库开发 Activity内存泄漏检测和同Bitmap创建。
- 当一个activity的mDestory为true,但是haha通过dump hprof 来做引用链分析,activity还是被引用。那么就表示泄漏了
15、OMM问题
1、java堆内存溢出
2、虚拟内存不够
3、无足够连续内存空间
4、FD数量超标
5、线程数超标
16、MAT中的重要概念
incoming references:C类的对象被A、B类引用,那么AB是C的incoming references outgoning references:C类中引用了D、E对象。那么DE是C的outgoning references
17、Android中加载一张图片所占用内存
- 如果粗略来讲就是:像素长度* 像素宽度 * 一像素字节大小,通常8888,4个字节。也有565。是2个字节。
- 如果严谨一点:(收集项目密度dpi/图片所放入的文件夹对应的像素密度dpi)^2)像素长度 像素宽度 * 一像素字节大小
18、压缩bitmap的小细节
try{
decode bitmap
}catch(outOfMemoryError e){
质量压缩
}
19、bitmap优化思路
总体思想: 1、设备分级,针对不同设备有不同的方案。
2、Bitmap优化 统一图片库 线上/线下监控
3、具体优化看官网。
20、leakcanary
具体可以看我的这篇文章,LeakCanary的实现原理 - 掘金 (juejin.cn)
过了5秒gc,再到引用队列里找一找看能不能找到引用。如果找到我就从watechedreferences中把他remove掉。如果还在我就加到怀疑列表中,retainedReferences。当怀疑列表个数大于5个就调用haha库的可达性分析来确认内存是否泄漏了。
比如Activity是否泄漏:判断实例是否是android.app.Activity 的子类,并且 mFinished 或 mDestroyed 是否为true(Activity 关闭时该值会为 true),因为Activity 不泄露的话肯定是会被释放,所以,不可能存在于dump的实例中,有就是发生了泄漏
然后通过引用链找到引起泄漏的元凶
21、其它小点
- runtime.getRuntime.GC不一定执行
- Matrix 检测到activity泄漏,则再ondestory中将素有成员和view置空。那么泄漏的也只是一个空壳问题不大。
- activity可以实现接口来收到 内存等级不够的通知。 implements componentCallbacks2
- 做内存优化,MAT的使用、profiler官方使用教程、koom一定要学。后续我出个教程
22、内存泄漏的原因
- 对象未及时释放:在Android开发中,如果创建了过多的对象,而这些对象没有被及时释放,就会导致内存泄漏。例如,在Activity或Fragment的生命周期中,如果持有过多的Bitmap对象,会导致Activity或Fragment无法被垃圾回收器回收,从而导致内存泄漏。
- 持有Context引用:在Android开发中,Context是一个非常重要的对象,但它也容易导致内存泄漏。如果一个对象持有Context的引用,而这个对象又不能被垃圾回收器回收,就会导致内存泄漏。例如,在Activity中持有Context的引用,但这个引用没有被及时释放,就会导致Activity无法被垃圾回收器回收,从而导致内存泄漏。
- 循环引用:在Android开发中,如果两个对象之间存在循环引用,即对象A持有对象B的引用,而对象B又持有对象A的引用,就会导致内存泄漏。例如,在Activity中存在一个View对象,而这个View对象又引用了Activity对象,就会导致Activity无法被垃圾回收器回收,从而导致内存泄漏。
- 资源未及时释放:在Android开发中,如果使用了大量的资源,如文件、数据库、网络连接等,而这些资源没有被及时释放,就会导致内存泄漏。例如,在使用Cursor时没有及时关闭Cursor对象,就会导致Cursor占用的内存无法被垃圾回收器回收,从而导致内存泄漏。
- ** 线程未正确管理**:在Android开发中,如果线程没有正确管理,也会导致内存泄漏。例如,在线程中创建了大量的对象,而这些对象没有被及时释放,就会导致内存泄漏。
- ** 静态变量**:在Android开发中,如果一个类中存在过多的静态变量,而这些变量没有被及时释放,就会导致内存泄漏。例如,在一个静态变量中引用了大量的对象,而这些对象没有被及时释放,就会导致内存泄漏。
- ** webview**
为了防止内存泄漏问题,可以采取以下措施1:
- 及时释放不再使用的对象:在开发过程中,要注意及时释放不再使用的对象,包括Bitmap、Context、Cursor等。
- 使用弱引用技术:对于一些不重要的对象,可以使用弱引用技术来避免对象的循环引用。例如,在Activity