hprof文件不仅仅只能排查oom,还能帮助我们排查验证一些奇奇怪怪的问题,下面是仅举了两个比如。期望经过这几个比如能拓宽大家排除crash的思路。
事例一
能够先考虑一下,遇到以下线上偶现的crash你会怎么去排查。
TransactionTooLargeException
分析
TransactionTooLargeException是什么
发生在 远程程序调用(remote procedure call), 这个过程中,参数和返回值会以 Parcel
存储 Binder 业务缓冲(transaction buffer)中,当参数和返回值过大,会发生该反常。
检查源码
这边我们能够发现可能是mState或许mPersistentState太大了,这边体系也有做相应信息的dumpStats
能够发现logcat里有以下信息
能够看出是fragment里面保存了太多东西。途径是androidx.lifecycle.BundlableSavedStateRegistry.key 下的android:support:fragments 下的android:support:fragments
检查代码能够知道android:support:fragments 保存的是下面的parcelable
经过体系的logcat我们只能知道这个FragmentManagerState的Parcelable保存数据太大了,详细是哪里还需求将parcelable转为FragmentManagerState再经过日志打印出来。
日志打印计划的缺点
为了找到详细哪个目标占用过大,我们先需求把Parcelable转为FragmentManagerState 这一步就比较麻烦了,需求嵌套循环的去打印
解决
既然是检查目标内存占用问题,其实我们能够经过检查hprof文件解决,在补获TransActionsTooLargeException反常一起去dump下当时的hporf文件 再经过hprof文件回捞排查问题。
经过回捞回来的hprof文件发现是这个CommunitySubTabModle创建了300多万个目标。(这儿也能够反过来证明打日志还需求操控好嵌套层数和数组大小,否则就是300w个目标的日志打印了)
这边也很容易想到是反解Parcelable的时分出问题了,检查代码改变 ,Parcelable目标确实新增了个两个字段,反解析的时分读了缓存的老内容导致顺序反常了 。
事例二
线上偶现crash 万分之一不到。
Restore的时分mActivie中的fragment找不到了,而mActive中fragment通常是在destroy时移除,结合调用途的代码猜想很有可能这个时分activity已经被destroy了。 怎么去验证呢。
我们相同经过crash时的hporf的保存和回捞。
调查viewpager2中保存的数据 找到包括crash信息中uuid的viewpager2,找到引用viewpager2的activity,承认确实已经被destroy了 而且这边activity也被泄漏了。
找到泄漏处代码
hprof回捞流程
现在仅适用于crash后dump。
- 安全中心装备 ,安全中心匹配到规矩后进行hprof dump
{
"crashId": "10993293", //crash 渠道crashid
"matchCrashType": "java.lang.IllegalStateException", //crash类型
"matchMessage": "Fragment no longer exists for key", //crash message
"matchMethod": "restoreState",//crash method 堆栈上一处匹配即可
"matchClass": "androidx.viewpager2.adapter.FragmentStateAdapter", //crash 类 堆栈上一处匹配即可
"dumpHprof": 1,//hprof dump开关
"crashTag": 0
}
-
完成dump后会产生埋点上报,需求依据crashId手动整理一波userid
-
运用文件回捞功能。
-
等候回捞成功告诉。