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

阿里一面之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.发送通知给用户。
  以上就是阿里面试后总结的几个要点,还不会的同学赶紧学起来吧,感谢您的阅读,创造不易,如果您觉得本篇文章对您有帮助,请点击关注小编,您的支持就是小编创作的最大动力!

Dota2小黑至宝出炉,几家欢喜几家愁?水友囤弓人哭晕在厕所哈喽大家好,这里是蜻蜓队长Zwj。许多朋友应该听说过Dota2的别名刀塔暖暖吧?作为一款偏硬核的Dotalike游戏,Dota2向来都是以高门槛高难度而著称的,这一点既是Dota2趁我睡着,你就去爸爸床!,7岁娃的灵魂拷问扎心了本文编辑旋妮审稿主任探长(共1872字,阅读时间约4分钟)前几天在网上看到了一篇文章,讨论了关于在什么时候和孩子分床睡的事,引起了很多妈妈的关注。而如何跟孩子分床,也是很多家长比较量子计算机如何检查错误?进行纠错时,一个量子比特的状态换到9个物理量子比特上。(图片来源SamuelVelascoQuantaMagazine)1994年,在新泽西州贝尔实验室工作的数学家彼得肖尔(Pet华为WatchD有望随MateV折叠屏手机23日一起发布,包装盒已曝光众所周知,本月华为将要发布的产品较多,前期泄露的折叠手机墨水平板华为WATCHFIT等,现在又泄露了华为可测量血压的手表,华为WatchD智能手表包装盒图。图片摘自网络从泄露的华为苹果AR头盔会干掉iPhone吗?iPhone13自发布以来广受好评,加量不加价,中国网友称赞其iPhone十三香。相关数据显示,iPhone在今年十月份销量同比增长46,时隔六年再度登顶中国市场,说通俗点儿,小米移动存储设备的抉择,移动固态硬盘和U盘谁更好用呢?其实现在网盘在一定程度上取代了移动存储设备,云端存储虽然夸平台用起来方便,但速度堪忧,而且数据存储在云端还有安全性的顾虑,所以现在各种移动存储产品还有很广阔的市场空间,U盘和移动硬杨雪15年后再度扮演江玉燕,不仅没有翻车,还美过当年?电视剧小鱼儿与花无缺可谓是一代90后95后甚至是00后的回忆,这部剧是根据古龙绝代双骄小说进行改编的剧版。该剧讲述的是双生兄弟小鱼儿与花无缺行走江湖过程当中发生的故事。除了主角小鱼北京首例比特币挖矿合同案宣判合同被认定无效12月15日,北京朝阳法院公开开庭审理并宣判了一起因比特币挖矿迟迟未见收益而引发的服务合同纠纷。法院一审认定合同无效,判决驳回原告要求支付巨额比特币收益的诉讼请求。据悉,该案系北京韦伯太空望远镜放置在阿丽亚娜5号火箭顶部准备发射韦伯太空望远镜放置在阿丽亚娜5号火箭顶部准备发射12月11日星期六,詹姆斯韦伯太空望远镜被放置在阿丽亚娜5号火箭上,该火箭将把它从法属圭亚那的欧洲太空港发射到太空。在到达最终组装大长时间穿高跟鞋,脚会怎么样?9个后果,你可能承受不了高跟鞋能增加身高,优化腿型身体曲线,纠正不良的姿势,又能提升气质,使得人们变得更加自信。然后,高跟鞋并不符合人体工学,长时间穿可能会造成脚变形,全身也会跟随着扭曲。穿高跟鞋时身体受魏大勋开车去杨幂酒店,第二天早上六点才离开,疑似研究剧本?十二月十号,魏大勋现身上海参加某时尚活动。活动在下午结束之后,魏大勋一个人开车来到杨幂剧组所在的酒店。当天杨幂拍完戏之后,也是从剧组离开,回到酒店之后就再也没有出去过了。当天魏大勋
乾隆第二次下江南在马陵山留下了民间爱情(一)作者雷斌乾隆年间,阳春三月,红花绿柳,暖风徐徐。一队皇家人马护卫着一辆黄篷金碾,自北向南浩浩荡荡。此乃是乾隆皇帝第二次下江南巡访。辗内传出乾隆帝的声音传和珅听旨。辗外太监高喊世台联公布另类榜单!男女磨王浮出水面,赵心童前五颜丙涛No。772022年5月25日消息,根据世界斯诺克巡回赛公布的一项另类榜单显示,202122赛季平均击球时间最快的5位球员依次是泰国一哥塔猜亚乌诺的17。7秒世锦赛七冠王罗尼奥沙利文的18。1700英镑一张!利物浦打击转卖欧冠门票的行为13张门票被取消据欧洲媒体报道,一些获得了通过投票购买门票权利的欧冠支持者们,试图在网上倒卖这些门票,标价起步为1700英镑。决赛一方利物浦俱乐部发现该行为后,果断采取措施,取消了13名球迷的冠军湖人与国王谈判顺利结束,2换1交易方案出炉5千万先生联手老詹对于湖人队的当家球星勒布朗詹姆斯来说,今天是一个特别的日子,因为NBA官方正式宣布了年度最佳阵容,勒布朗詹姆斯成功入选三阵,值得一提的是这是老詹职业生涯至今第18次入选最佳阵容了,3个不要,让你远离尿毒症尿毒症虽然听着离我们的生活挺远的,但肾脏疼了累了不会说话。当你看到镜子里的自己脸部水肿,小便发现血尿,或者发现自己尿量明显变少了,又或者贫血了,这时很可能是肾在跟你报警了。如果身体盘点那些穿旗袍很美的女明星,赵丽颖直接被芒果台收录影像盘点那些穿旗袍很美的女明星,赵丽颖直接被芒果台收录影像!旗袍真是一个神奇的存在呢,美如女明星也不是谁穿都好看,有人穿得有韵味,身段迷人,有的却显得很奇怪。汤唯,许多网友说汤唯演的王这些洗面奶可彻底清除毛孔深处的污物,彩妆和灰尘,令肌肤更洁净这些洗面奶可彻底清除毛孔深处的污物,彩妆和灰尘,令肌肤洁净清纯!花钰集氨基酸洗面奶花钰集氨基酸洗面奶被广大网友评为国货之光,深层洁面的同时温柔呵护肌肤,保留滋润水分并且彻底清洁毛孔看看古代美妆穿搭博主的祖奶奶是什么样的?一个男人做了错事,但凡他身边有个美丽的女人,那么她总会被认为是祸水。而祸水这个典故,就是从赵飞燕,赵合德两姐妹而来。从小被父母弃养,赵飞燕是怎样从孤女崛起成皇后,赵合德又是怎样让皇会选,会看,会烹这些膳食好习惯,帮你吃出健康不合理的膳食结构正在悄悄地损害我们的健康。2018年全球营养报告指出,全球近五分之一的死亡与饮食相关,其中主要原因是高盐,全谷物水果坚果摄入量少,以及能量不平衡。既然膳食结构对我们为啥晚上不能吃红苋菜?医生尽量不要和这2种食物同吃,了解下送走了春天的野菜山珍,又迎来了初夏的应季时蔬,今天分享的食材不同于其他蔬菜的绿,而是呈现红色的苋菜。爱乐养生民间有话说得好五月苋菜正当时,六月苋菜当鸡蛋,七月苋菜金不换,可以看出民再见艾顿!太阳酝酿4换1交易抢33岁巨星重组三巨头争冠太阳在西部半决赛出局之后,艾顿与球队的续约问题成为了媒体关注的焦点。根据亚利桑那晚报记者透露的消息,由于在季后赛抢七大战中仅出战16分钟,艾顿百思不得其解,他和主帅蒙蒂威廉姆斯之间