范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

阿里一面之LeakCanary内存泄漏监测原理总结

  本文通过在阿里面试遇到的问题总结而出,如有不对地方,请及时批评指正。篇幅较长,请耐心阅读。简介:
  LeakCanary是一个开源的内存泄漏检查工具,使用简单,主要用来监测Activity和Fragment是否发生内存泄漏。如果发生内存泄漏,直接以引用链的形式展示出造成内存泄漏对象。使用步骤添加build.gradle依懒。  debugImplementation "com.squareup.leakcanary:leakcanary-android:1.6.3"   releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:1.6.3"   debugImplementation "com.squareup.leakcanary:leakcanary-support-fragment:1.6.3"
  2.在Application中初始化LeakCanary。class CustomApplication:MainApplication() {     override fun onCreate() {         super.onCreate()        if (! LeakCanary.isInAnalyzerProcess(this)) {             LeakCanary.install(this);         }     } }
  完成以上两步操作之后,当打开app运行时,如果Activity或Fragment发生内存泄漏,会以通知的形式提醒用户。源码分析
  先通过流程图来看一下LeakCanary工作原理,如图所示:
  LeakCanary初始化
  1.在application中注册。class CustomApplication:MainApplication() {     override fun onCreate() {         super.onCreate()        if (! LeakCanary.isInAnalyzerProcess(this)) {            //注册leakcanary             LeakCanary.install(this);         }     } }
  2.构建观察者RefWatcher。public static RefWatcher install(Application application) {     //构建观察者RefWatcher     return refWatcher(application).listenerServiceClass(DisplayLeakService.class)         .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())         .buildAndInstall(); }
  3.构建不同的观察者ActivityRefWatcher或FragmentRefWatcher。public RefWatcher buildAndInstall() {     if (LeakCanaryInternals.installedRefWatcher != null) {       throw new UnsupportedOperationException("buildAndInstall() should only be called once.");   }     RefWatcher refWatcher = build();     if (refWatcher != DISABLED) {         //观察activity       if (watchActivities) {         ActivityRefWatcher.install(context, refWatcher);     }       //观察fragment       if (watchFragments) {         FragmentRefWatcher.Helper.install(context, refWatcher);     }   }     LeakCanaryInternals.installedRefWatcher = refWatcher;     return refWatcher; }
  4.监测activity生命周期。public static void install(Context context, RefWatcher refWatcher) {     Application application = (Application) context.getApplicationContext();     ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);    //注册生命周期     application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks); }
  5.将观察对象activity添加到被观察者队列。private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =     new ActivityLifecycleCallbacksAdapter() {         @Override public void onActivityDestroyed(Activity activity) {             //在activity的onDestroy生命周期中添加观察对象           refWatcher.watch(activity);       }     };泄漏检测
  1.将被观察对象包装成弱引用。public void watch(Object watchedReference, String referenceName) {     if (this == DISABLED) {       return;   }      //判空检查     checkNotNull(watchedReference, "watchedReference");     checkNotNull(referenceName, "referenceName");     final long watchStartNanoTime = System.nanoTime();     //生成唯一key     String key = UUID.randomUUID().toString();     //保存key     retainedKeys.add(key);     //包装成弱引用对象     final KeyedWeakReference reference =     new KeyedWeakReference(watchedReference, key, referenceName, queue);     //检查被观察对象是否被回收     ensureGoneAsync(watchStartNanoTime, reference); }
  2.检测弱引用对象是否被回收。@SuppressWarnings("ReferenceEquality") // Explicitly checking for named null. Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {     long gcStartNanoTime = System.nanoTime();     long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);     //移除被回收对象的key     removeWeaklyReachableReferences();      if (debuggerControl.isDebuggerAttached()) {       // The debugger can create false leaks.       return RETRY;   }     //判断弱引用是否被回收     if (gone(reference)) {       return DONE;   }     //触发系统GC进行垃圾回收     gcTrigger.runGc();     //再次移除被回收对象的key     removeWeaklyReachableReferences();     //判断弱引用对象是否被回收     if (!gone(reference)) {         //将没有被回收对象的内存快照保存成文件       long startDumpHeap = System.nanoTime();       long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);        File heapDumpFile = heapDumper.dumpHeap();       if (heapDumpFile == RETRY_LATER) {         // Could not dump the heap.         return RETRY;     }       long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);       //构建内存快照文件       HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)           .referenceName(reference.name)           .watchDurationMs(watchDurationMs)           .gcDurationMs(gcDurationMs)           .heapDumpDurationMs(heapDumpDurationMs)           .build();       //将内存信息回调出去       heapdumpListener.analyze(heapDump);   }     return DONE; }内存分析
  1.启动HeapAnalyzerService进行内存分析@Override public void analyze(HeapDump heapDump) {     checkNotNull(heapDump, "heapDump");     HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass); }
  2.保存文件,并发送通知给用户@Override protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {     String leakInfo = leakInfo(this, heapDump, result, true);     CanaryLog.d("%s", leakInfo);      boolean resultSaved = false;     boolean shouldSaveResult = result.leakFound || result.failure != null;     if (shouldSaveResult) {      //保存内存文件       heapDump = renameHeapdump(heapDump);       resultSaved = saveResult(heapDump, result);   }      PendingIntent pendingIntent;     String contentTitle;     String contentText;     //解析内存文件     if (!shouldSaveResult) {       contentTitle = getString(R.string.leak_canary_no_leak_title);       contentText = getString(R.string.leak_canary_no_leak_text);       pendingIntent = null;   } else if (resultSaved) {       pendingIntent = DisplayLeakActivity.createPendingIntent(this, heapDump.referenceKey);        if (result.failure == null) {         if (result.retainedHeapSize == AnalysisResult.RETAINED_HEAP_SKIPPED) {           String className = classSimpleName(result.className);           if (result.excludedLeak) {             contentTitle = getString(R.string.leak_canary_leak_excluded, className);         } else {             contentTitle = getString(R.string.leak_canary_class_has_leaked, className);         }       } else {           String size = formatShortFileSize(this, result.retainedHeapSize);           String className = classSimpleName(result.className);           if (result.excludedLeak) {             contentTitle = getString(R.string.leak_canary_leak_excluded_retaining, className, size);         } else {             contentTitle =             getString(R.string.leak_canary_class_has_leaked_retaining, className, size);         }       }     } else {         contentTitle = getString(R.string.leak_canary_analysis_failed);     }       contentText = getString(R.string.leak_canary_notification_message);   } else {       contentTitle = getString(R.string.leak_canary_could_not_save_title);       contentText = getString(R.string.leak_canary_could_not_save_text);       pendingIntent = null;   }     // 每次发送一个新通知提醒用户。     int notificationId = (int) (SystemClock.uptimeMillis() / 1000);     showNotification(this, contentTitle, contentText, pendingIntent, notificationId);     afterDefaultHandling(heapDump, result, leakInfo); }
  整个监测过程主要作用如下:
  1.注册监听activity生命周期。
  2.在activity被销毁时加入弱引用队列。
  3.第一次移除不可达对象,移除ReferenceQueue中的KeyedWeakReference。
  4.主动触发GC进行垃圾回收。
  5.第二次移除不可达对象,移除ReferenceQueue中的KeyedWeakReference。
  6.判断当前是否还有对象存活,如果有保存存活对象的内存快照heapDumpFile,然后进行内存分析。
  7.启动HeapAnalyzerService对内存快照进行分析,找出GCroots引用链。
  8.发送通知给用户。
  以上就是阿里面试后总结的几个要点,还不会的同学赶紧学起来吧,感谢您的阅读,创造不易,如果您觉得本篇文章对您有帮助,请点击关注小编,您的支持就是小编创作的最大动力!

要换汽车轮胎了,想优先考虑国产品牌,现在比较火的有哪些?我的原车胎是固特异,后来换过广州产万力,跑了4年8万多公里,现在换了双星,胎噪静音透水性和耐磨度都好于固特异,操控性也不差,国产轮胎物美价廉不用优先,没钱直说。捂脸国产轮胎都差不多您对网红美食有什么评价,买过哪些好的美食,是否入坑?在中关村的食宝街吃过各类美食,网红美食确实人更多更好吃,例如冷面王,花甲粉,鸡爪等。玫瑰很荣幸回答您的问题可爱玫瑰我们先来说说网红美食,网红美食分两种情况,一种是商家花钱炒作出来的你有没有旅行到了一个地方后,先寻找的是当地的特色美食?很高兴回答题主的问题你有没有旅行到了一个地方后,先寻找的是当地的特色美食?今年七月末和八月初,外甥姑爷和外甥女带我和老伴去广东的汕尾暂短旅行。除了游山玩水外就是寻找当地的特色美食大大家喜欢穿什么品牌的卫衣,都在哪里买?好看便宜质量好绝对的物美价廉!下面我推荐几件实名认证好看价格适中,质量好的卫衣啦!第一件tb搜店名潮服hurtmyself关键词日系,复古,慵懒整个一绝又便宜又好穿面料也舒服,随便如果让清华北大的专家教授到一个办学条件比较差的农村中学去任教,他们会怎样面对?清华北大的专家教授到农村学校去任教,这是一个不错的想法,他们即使到较差的农村学校去教书,比我们想象的效果要好。很多人想借此贬低名牌大学的专家教授,这种想法是不纯正的。北大清华的专家株洲有什么好玩的地方?醴陵陶瓷艺术城涵盖了陶瓷博物馆李铎将军艺术馆图兰朵酒店和大型雕塑广场等,艺术城建成后,醴陵市将成为世界陶瓷艺术一站式体验中心和世界艺术家的聚会中心客旅创作中心,同时还将成为世界艺术一位私立学校的教师,成绩优秀,班级管理好,却因得罪了领导被辞退,对此,你怎么看?本人在私立学校干过,正好有被辞的经历。2002年,我从县一中辞职到一所私立学校任职高二两个班语文课,任班主任,教研组长。二十多年一中语文教学的经验,正值年富力强,可以承受优秀教师的28岁的人在长沙月薪多少才算合格?首先我们来看一下长沙的整体薪资报告得出的长沙整体平均工资在3900元左右。长沙在整个中国城市当中虽然不在一线城市之列,但是消费水平却始终在向一线水平看齐,所以3900块钱只能勉强让你认识的高考超常发挥考入名校的人,后来怎么样了?高中男同学,高三第一学期还在上课睡觉看金庸小说练钢笔字谈恋爱,那女生是班里学习非常好的。他的钢笔字写的真是有一定的水准了,那时候特别流行抄歌词,谁有一盘流行歌曲磁带借过来听完了还要怎么做好糕点?想学习做糕点该去哪里学?这问题太广泛,糕点分很多种的,是具体想学习哪一些呢1。可以下载一些厨艺app,里面会有详细的教程。2。可以多看一些制作甜品过程的视屏。推荐b站的甜品大师,这是一个制作甜品竞赛的节目西宁最高的楼有哪些?西宁市已经建成的最高楼万达广场,180米建筑高度180米。项目位于海湖广场以南,甲级写字楼建筑面积约14万平方米,高度为180米另有4栋乙级写字楼,高度也在100米以上。西宁正在建
紫金e评实干有为启新程习近平总书记在二二三年春节团拜会上指出,新征程是充满光荣和梦想的远征,没有捷径,唯有实干,为者常成,行者常至,历史不会辜负实干者。我们靠实干创造了辉煌的过去,还要靠实干开创更加美好要维护好送亲人最后一程的权益郭元鹏因父亲癌症晚期病重,男子李某向公司请假一周看护。在请假未获批准的情况下,李某因父亲癌症晚期病重,2022年1月21日20时45分李某通过邮箱向张某胡某等三位公司领导发送了邮件曹休曹家千里驹惭恨败石亭三国魏明帝太和二年(228年),东吴鄱阳太守周鲂称得罪吴王,要携郡降魏。魏大司马扬州牧曹休闻讯大喜,亲率十万军士前往接应,不想中诈降之计,在石亭被吴将陆逊朱桓全琮截击,魏军被斩杀万莫兰特为什么尊敬詹姆斯,却不把乔丹放在眼里,难道只是轻狂吗莫兰特除了打球风格很劲爆之外,他的性格也是非常的直爽,想到什么就说什么,绝不会因为你是前辈就假意尊重。莫兰特是如今NBA唯一一个敢说敢做的球员。美国媒体一直热衷于问年轻球员一些比较菲尔汉迪科比说得分后卫就是得分防守这和传球无关直播吧1月25日讯近日,湖人助教菲尔汉迪在一档节目中谈到了一则科比趣事。汉迪表示当时科比在向米克斯解释什么是得分后卫,他说我是一个得分后卫,所以我得分防守。这里面和传球可没什么关系科尔谈维金斯他受伤前打得很好但自从伤愈归队后有些沮丧直播吧1月25日讯今日勇士主帅科尔在球队训练结束后接受了媒体采访。谈到维金斯近期低迷状态,科尔表示我认为长时间的缺席确实伤害了他,这是他职业生涯中第一次经历这样的事情,在赛季中期复KG赛前推特这是塔图姆扛着球队的夜晚他能在MVP履历留个印记直播吧1月25日讯今日NBA常规赛,凯尔特人在客场以9598惜败于热火。此役,凯尔特人布朗斯玛特霍福德和布罗格登等多人缺阵,塔图姆单核带队。赛前,加内特更推道这是塔图姆扛着球队前进埃尔南戈麦斯感觉我最后在空位,无法取胜让我难过鹈鹕主场逆转失败,以9899惜败于掘金。鹈鹕球员威利埃尔南戈麦斯打了23分钟,拿到了12分6篮板2助攻。埃尔南戈麦斯表示,他感觉自己最后一个回合在空位,他称赫伯特琼斯因为没有传球已新年第一战U20国足阿联酋热身赛1比1平阿曼安东尼奥和邵佳一搭档率领的中国U20男足国家队迎来西亚拉练的第3场热身赛。凭借艾菲尔丁的进球,U20国家队以1比1与阿曼U20握手言和。1月17日抵达阿联酋开启海外拉练以来,U20阿德巴约3015塔图姆31147巴特勒ampampamp布朗缺战热火险胜绿军直播吧1月25日讯NBA常规赛,热火今日迎战凯尔特人,前者上场比赛战胜鹈鹕位列东部第六位,后者则是不敌魔术继续高居东部榜首的位置,此役布朗斯玛特霍福德布罗格登和巴特勒等人缺战。比赛诚意满满!皮尔洛再次亲笔信向中国球迷拜年,手绘兔子涂鸦直播吧1月25日讯继去年春节亲笔写信向中国球迷拜年后,今年意大利名宿现执教于土超卡拉古姆鲁克的皮尔洛再次亲笔写信向中国球迷送上了兔年的祝福,他还涂鸦了一只兔子。皮尔洛今年写信拜年内