Android 12原生系统居然有内存泄漏隐患?

程序员 2024-9-11 23:00:55 87 0 来自 中国
作者:作者:努比亚技术团队
Android内里内存泄漏标题最突出的就是Activity的泄漏,而泄漏的根源大多在于由于生命周期较长的对象去引用生命周期较短的Activity实例,也就会造成在Activity生命周期竣过后,还被引用导致无法被系统接纳开释。
Activity导致内存泄漏有两种情况:

  • 应用级:应用步伐代码实现的activity没有很好的管理其生命周期,导致Activity退出后仍然被引用。
  • 系统级:Android系统级实现的对activity管理不太友好,被应用调用导致内存泄漏。
本文重要讲的是近来发现的系统级shouldShowRequestPermissionRationale方法使用导致的内存泄漏标题。
一、配景

Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再须要扣问用户。在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的须要动态获取。重要流程如下:
这个过程中会碰到这么几个方法:

  • ContextCompat.checkSelfPermission,查抄应用是否有权限
  • ActivityCompat.requestPermissions,哀求某个或某几个权限
  • onRequestPermissionsResult,哀求权限之后的授权效果回调
  • shouldShowRequestPermissionRationale
前三个方法的用途都非常清楚,使用也很简单,这里不做过多表明,本日重要看下shouldShowRequestPermissionRationale,看下它是干什么用的:
当APP调用一个须要权限的函数时,假如用户拒绝某个授权,下一次弹框时将会有一个“禁止后不再扣问”的选项,来防止APP以后继续哀求授权。假如这个选项在拒绝授权前被用户勾选了,下次为这个权限哀求requestPermissions时,对话框就不弹出来了,效果就是app啥都不干。碰到这种情况须要在哀求requestPermissions前,查抄是否须要展示哀求权限的提示,这时间用的就是shouldShowRequestPermissionRationale方法。
shouldShowRequestPermissionRationale字面表明是“应不应该表明下哀求这个权限的目的”,下面摆列了此方法使用时的4种情况及相应情况下的返回值:

  • 都没有哀求过这个权限,用户不愿定会拒绝你,以是你不消表明,故返回false;
  • 哀求了但是被用户拒绝了,此时返回true,意思是你该向用户好好表明下了;
  • 用户选择了拒绝而且不再提示,也不给你弹窗提示了,以是你也不消表明了,故返回fasle;
  • 已经允许了,不须要申请也不须要提示,故返回false。
二、调用案例及内存泄漏隐患

2.1正常权限申请流程

通常我们申请权限时先调用checkSelfPermission方法查验应用是否有须要使用的权限,没有相应权限时调用shouldShowRequestPermissionRationale方法查抄是否须要展示哀求权限的提示。不须要展示提示时再调用requestPermissions方法进行权限哀求。代码如下:
2.png 2.2内存泄漏隐患发现

在Android S上,我们使用上述方式进行权限获取时会发现只要你调用了shouldShowRequestPermissionRationale方法,当MainActivity生命周期竣过后MainActivity都不会被接纳。我们可以不给予所需权限多次进入退出此应用运行一段时间(包管每次都会调用到shouldShowRequestPermissionRationale方法)。使用adb下令dump meminfo检察内存情况。可以看到activity实例数为25,表明acticity虽然被烧毁但是由于被其他对象持有以是并没有被GC。 留意:此处测试是通过返回键退出activity的,我们的Demo在返回键的监听有调用finish方法确保竣事activity。每次重新进入都会重新实行onCreate方法。由于Android S上使用返回键退出应用并不会直接烧毁activity,而只有当应用主动调用finish大概非启动范例的activity才会去烧毁。
3.png 此时我们已经发现此Demo存在显着的内存泄漏标题。下面我们使用Memory Profiler工具抓取hprof文件进行内存分析,看看是那里发生了内存泄漏。

  • 可以看到Memory Profiler工具已经提示我们有com.nubia.application包下MainActivity有24个对象发生了内存泄漏。
  • 可以看到当前MainActivity统共实例有25个和adb下令查询出来符合。其他24个实例没有被GC导致内存泄漏。
  • References标签页可以看到其他MainActivity实例被AppOpsManager持有导致无法被GC。
  • 我们可以看到Memory Profiler工具提示共有48个对象产生内存泄漏那么其他24个是那里产生的呢?点击Leaks进行检察如下图。
    5.png

  • 可以看到除了MainActivity产生了内存泄漏,ReportFragment也产生了内存泄漏。检察ReportFragment的Instance Details标签页可以看到ReportFragment的实例被MainActivity持有而MainActivity被AppOpsManager持有以是产生了内存泄漏。
  • 至此Demo中全部内存泄漏标题分析完成。
2.3内存泄漏隐患分析

在上一节中我们已经发现Demo在使用过程中存在内存泄漏标题。只要我们调用shouldShowRequestPermissionRationale方法,当Activity生命周期竣事时就会发生Activity内存泄漏。那么这一节我们来具体分析下为什么调用shouldShowRequestPermissionRationale方法会发生内存泄漏。
我们先来看一下shouldShowRequestPermissionRationale方法调用整个过程的时序图:
看完调用流程图后,我们再来一步一步分析shouldShowRequestPermissionRationale具体是怎么调用的,以及为什么会产生内存泄漏?
先从Activity的shouldShowRequestPermissionRationale方法开始,Activity调用的是packageManager的shouldShowRequestPermissionRationale方法。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2025-2-23 06:40, Processed in 0.155793 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表