什么是内存走漏
关于不同的言语渠道来说,进行符号收回内存的算法是纷歧样的,像Android(Java)则选用GC-Root的符号收回算法。下面这张图就展现了Android内存的收回办理战略(图来自Google 2011的IO大会)
图中的每个圆节点代表目标的内存资源,箭头代表可达途径。当圆节点与GC Roots存在可达途径时,表明当时资源正被引证,虚拟机是无法对其进行收回的(如图中的黄色节点)。反过来,假如圆节点与GC Roots不存在可达途径,则意味着这块目标的内存资源不再被程序引证,体系虚拟机能够在GC进程中将其收回掉。
有了上面的内存收回的栗子,那么接下来就能够说说什么是内存走漏了。从界说上讲,Android(Java)渠道的内存走漏是指没有用的目标资源任与GC-Root坚持可达途径,导致体系无法进行收回。举一个最简略的栗子,咱们在Activity的onCreate函数中注册一个播送接收者,可是在onDestory函数中并没有履行反注册,当Activity被finish掉时,Activity目标现已走完了自身的生命周期,应该被资源收回释放掉,但因为没有反注册,此刻Activity和GC-Root间任然有可达途径存在,导致Activity尽管被毁掉,可是所占用的内存资源却无法被收回掉。相似的栗子其实有许多,纷歧一例举了。
走漏的源头了解完内存走漏的理论知识后,再来归类一下内存走漏的源头。这儿我将其归位以下三类:
自身编码引起
由项目开发人员自身的编码形成。
第三方代码引起
这儿的第三方代码包括两类:第三方非开源的SDK和开源的第三方结构。
体系原因
由Android体系自身形成的走漏,如像WebView、InputMethodManager等引起的问题,还有某些第三方ROM存在的问题。
走漏的定位
内存走漏不像闪退的BUG,排查起来相对要比较困难些,比较极点的状况是当你的运用OOM了才发现存在内存走漏问题,到了这种状况才去排查处理问题的话,对用户的影响就太大了。为此,咱们能够在编码中尽早发现到问题就不要拖到上线之后才去填坑,下面介绍一些我比较常用排查内存走漏的东西。
静态代码剖析东西——Lint
Lint是Android Studio自带的东西,运用姿态很简略Analyze -> Inspect Code然后挑选想要扫面的区域即可
对或许引起走漏的编码,Lint都会进行温馨提示。
这儿仅仅抛砖引玉的介绍Lint,实际上玩法还有许多,咱们能够自行拓宽学习。除了Lint外,还有像FindBugs、Checkstyle等静态代码剖析东西也是很不错的。
苛刻形式——StrictMode
StrictMode是Android体系供给的API,在开发环境下引进能够更早的露出发现问题。官方文档链接在下面(需求科学上网):
https://developer.android.com/reference/android/os/StrictMode.html
以官网的示例代码为栗子,一般StrictMode只在测验环境下启用,到了出产环境就会进行封闭,一般咱们都会凭借BuildConfig.DEBUG来完结。
启用StrictMode后,在过滤日志的当地加上StrictMode的过滤Tag,假如手机连接着电脑进行开发,定时调查一下StrictMode这个Tag下的日志,一般你看到一大堆赤色告警的Log,就需求好好排查一下是否跟内存走漏有关了。
LeakCanary
Square公司出品的内存剖析东西,官方地址如下:
https://github.com/square/leakcanary/
LeakCanary和StrictMode相同,需求在项目代码中集成,不过代码也十分简略,如下的官方示例。
build.gradle引进,Application中参加两三行代码,即可搞定。以上仅仅简略的引进,还有更多运用姿态主张具体阅览它的Wiki下FAQ:
https://github.com/square/leakcanary/wiki/FAQ
我对运用LeakCanary有以下两点感触:
当内存走漏发生时,LeakCanary会弹窗提示并生成对应的堆存储信息记载,这让咱们对荫蔽的内存走漏问题有了愈加直观的感觉,但从实际运用来看,LeakCanary的每个提示也并非是真实存在内存走漏问题,要想确认是否存在问题咱们还需求凭借MAT来进行终究的确认。
Android体系自身就存在一些问题导致运用内存走漏,LeakCanary的 AndroidExcludedRefs 类协助咱们处理了不少这类问题。
Android Memory Monitor
AndroidStudio供给的东西,用于监控运用的内存运用状况,在开发中也是十分有用的东西,能够用来打印出内存的状况信息。
打印获得的内存信息如下,能够经过右上角的绿色三角形按钮去剖析走漏的Activity和一些重复的字符串,现在只支撑这两个,期望Google后边能够参加更多可选剖析规矩
相同,这儿也仅仅抛砖引玉的简略介绍,关于它的运用在官方文档现已说得很具体了,需求的童鞋自行检查下方链接(需科学上网):
https://developer.android.com/studio/profile/am-hprof.html
Memory Analyzer (MAT)
老牌子剖析东西,能够从 http://www.eclipse.org/mat/ 下载获得,网上关于MAT运用的文章许多,咱们能够自行查找。上面的Android Memory Monitor生成的对贮存信息文件能够装备MAT一起来剖析运用,因为Android Memory Monitor生成的hprof文件不是规范格局,所以需求做一下转化,然后导入MAT
然后经过OQL先定位出走漏的目标
经过扫除除了强引证之外的其他引证链,终究剖析到GC Root的方位
MAT运用起来相对繁琐,但不失为定位本源问题的利器。
adb shell指令
运用adb shell dumpsys meminfo [PackageName],能够打印出指定包名的运用内存信息
运用该指令能够很直观的调查到Activity的走漏问题,是我往常剖析比较常用的一种办法。除了运用指令外,AndroidStudio也供给了下面的功用,和运用指令是相同作用的。
假如对adb shell指令感兴趣,更多的信息能够看下面供给的资源:
http://adbshell.com/
https://github.com/mzlogin/awesome-adb
以上便是我在做内存走漏剖析的时分会用到的东西,一般都是结合起来用,究竟每个东西都有优缺点,经过运用多个东西互补剖析问题能够极大的进步咱们的功率和终究获得的作用。
走漏的处理议计划
略聊完东西,终究来谈谈内存走漏问题的处理战略。我把它总结为以下三点:
完结需求功用开发后,再去优化内存走漏问题;
走漏源有多处时,中心功用发生的走漏优先处理,用户运用频频的功用引起的走漏优先处理;
处理走漏防止影响原有的代码逻辑,优化往后最好能够让测验童鞋过一遍相关的功用,防止引进不知道的BUG;
总结
关于怎么在编码上去处理内存走漏问题,网络上有供给了许多场景及其处理方案,咱们能够自行凭借搜索引擎。经过把握剖析办法和对走漏场景及其处理方案的堆集,信任咱们处理内存走漏问题是挥洒自如的。当然,也并不是一切内存走漏问题咱们都能够进行处理,就例如第二章节说到的走漏源头是由第三方代码引起时,咱们就显得力不从心了。最近在排查的进程中就发现不少第三方SDK存在走漏问题,遇上这种状况就得找找可代替的SDK进行更换了。以上便是我做内存走漏剖析的一些心得总结,假如有过错和缺乏,还请咱们指出。