Android Native Leak分析

2023-05-16

Native Heap 为 Android C++层(也为so库)所分配的内存


    • 问题描述
    • 解决方式
    • 数据分析
      • 问题
      • 解决方法
      • 获取数据方法
      • 脚本 python3
      • 解析结果
    • 出现问题
    • 技巧

问题描述

使用dumspsys meminfo 发现 native heap持续增长
NativeHeap

解决方式

使用ddms插件分析Native Heap,可以获取到app从开始运行到点击时所有native heap的申请状况。
步骤
- 设置malloc debug模式
7.0之前 setprop libc.debug.malloc 1
7.0之后 setprop libc.debug.malloc.options backtrace
- 重启android服务
adb shell stop
adb shell start
- 查看so在android系统上的映射位置
cat /proc/<pid\>/maps | egrep /lib/arm/lib.*\.so | grep r-xp
需在app运行时查看

d70c3000-d7130000 r-xp 00000000 fc:02 11140      /a.so
d7150000-d7184000 r-xp 00000000 fc:02 11134      /b.so
d71dd000-d71e7000 r-xp 00000000 fc:02 11136      /c.so
d7206000-d723f000 r-xp 00000000 fc:02 11139      /d.so
e4f0c000-e4f18000 r-xp 00000000 fc:02 11135      /e.so
  • 解析申请Native Heap位置
    addr2line -Cfe lib*.so [addr]
    如出现问题查看[1]

数据分析

问题

由于查看的是video的native stack 溢出,使用ddms.bat时,很容易造成卡死

解决方法

将数据保存至本地,自行分析

获取数据方法

这里写图片描述
点击红框会出现很长时间的卡顿,接着会出现如下状况
这里写图片描述
此时还不能保存,因为还没有解析出lib.so名称,而且若此时点击保存同样会造成卡死,需要等到如下图所示,才可以保存。
解析时间巨长
Alt text

这里写图片描述
出现上图,则表示解析完毕,可以将数据进行保存
单个数据样式如下

Allocations: 1
Size: 614400
TotalSize: 614400
BeginStacktrace:
    d7a1127e    /lib/arm/a.so --- d7a1127e --- 
    d7a110e2    /lib/arm/a.so --- d7a110e2 --- 
    d7775f92    /lib/arm/b.so --- d7775f92 --- 
    d777614e    /lib/arm/b.so --- d777614e --- 
    d7773950    /lib/arm/b.so --- d7773950 --- 
    d777381c    /lib/arm/b.so --- d777381c --- 
    d777399c    /lib/arm/b.so --- d777399c --- 
    f42d9d4e    /system/lib/libc.so --- f42d9d4e --- 
    f42ad038    /system/lib/libc.so --- f42ad038 --- 
EndStacktrace

当保存完成后,建议重新打开ddms获取下一次数据

脚本 python3

思路
- 提取数据(不包含官方so)
- 相同数据,不添加到新链表,使用计数
- 按照size大小由大到小排序,若相同看第一个库的地址排序
- 比较两个链表计数数据,提取差值数据
- 通过so在Android中maps的映射位置,计算偏移量
链表 解析出来的Native Heap

#Parse Native heap from DDMS's Native Heap save
import linecache
import re

# Compare Files
FileName0 = "C:\\Users\\*\\Desktop\\memCrash\\allocations61.txt"
FileName1 = "C:\\Users\\*\\Desktop\\memCrash\\allocations64.txt"

app_lib  = {
'a.so' :   0xd70c9000, 
'b.so' :   0xd715d000, 
'c.so' :   0xd71d6000, 
'd.so' :   0xd7206000, 
'e.so' :   0xe4f23000
}

def parseNativeHeap(str):
    temp  = re.match(r'\t([0-9,a-f]{8}).*/([^/]*)\s---\s[0-9,a-f]{8}.*', str)
    key   = int(temp.group(1), 16)
    value = temp.group(2)

    # Remove system library
    if value not in app_lib:
        key = 0
        value = 0

    return key, value

def isNatvieSame(list1, list, list_num):
    # Remove empty list
    if len(list1) <= 1:
        return 1

    if len(list) >= len(list_num):
        list_num.append(1)

    if list1 in list:
        nbr = list.index(list1)
        list_num[nbr] += 1
        return 1
    return 0

# list sort
def addAndSortList(list1, list):
    if len(list) == 0:
        list.insert(0, list1)
        return

    for i in range(0, len(list)):
        # list中 0 = size, 1 = lib,2 = addr
        # 判断顺序
        ## 判断size,从大到小
        ## 地址从大到小
        if list1[0] < list[i][0] and (i + 1 == len(list) or list1[0] > list[i+1][0]):
            list.insert(i + 1, list1)
            return
        elif list1[0] == list[i][0]:
            # print(list1, "------", list[i],  "------", i, len(list))
            # 如果地址小 且 (下一个值不是终点 或 下一个值size不同 或 地址大于下一个值)
            if list1[2] < list[i][2] and (i + 1 == len(list) or list1[0] != list[i+1][0] or list1[2] > list[i+1][2]):
                list.insert(i + 1, list1)
                return

    list.append(list1)


def countNativeHeap(file_name):
    lineLen  = len(open(file_name, 'r').readlines())
    lineStrs = linecache.getlines(file_name)

    list = []
    list_num = []
    for i in range(0, lineLen):
        line = lineStrs[i]

        # Pass blank line
        if len(line) < 10:
            continue

        name = line.split(':')[0]

        if   name == "Allocations":
            list1 = []
        elif name == "Size":
            continue
        elif name == "TotalSize":
            list1.append(int(line.split(':')[1]))
        elif name == "BeginStacktrace":
            continue
        elif name == "EndStacktrace\n":
            if not isNatvieSame(list1, list, list_num):
                addAndSortList(list1, list)
        else:
            key, value = parseNativeHeap(line)
            if key != 0:
                list1.append(value)
                list1.append(key)

    # print(len(list))
    # print(list_num)

    return list, list_num

# Get Native List
list1, list1_num = countNativeHeap(FileName0)
list2, list2_num = countNativeHeap(FileName1)

print('len', len(list1), len(list2))
# print(list1)

# In second list find first element
def findDiffStack(first, second, first_num, second_num, diff, diff_num, noneExist, noneExist_num):
    for i in second:
        second_nbr = second.index(i)
        if i in first:
            first_nbr = first.index(i)
            noneExist_size = second_num[second_nbr] - first_num[first_nbr]
            if noneExist_size != 0:
                diff.append(i)
                diff_num.append(noneExist_size)
        else:
            noneExist.append(i)
            noneExist_num.append(second_num[second_nbr])

# 变化值
list_diff = []
list_diff_num = []
# 不存在值
list_noneExist = []
list_noneExist_num = []

findDiffStack(list1, list2, list1_num, list2_num, list_diff, list_diff_num, list_noneExist, list_noneExist_num)

print('diff     ', len(list_diff_num),  'size', list_diff_num)
print('noneExist', len(list_noneExist), 'size', list_noneExist)

# Caculate native heap create addr
def caculateAddr(src, orgin):
    for i in src:
        for j in range(1, len(i), 2):
            key = i[j]
            if i[j] in orgin:
                i[j + 1] -= orgin.get(i[j])

caculateAddr(list_diff, app_lib)
caculateAddr(list_noneExist, app_lib)

# Display
def displayResult(list, num):
    for i,z in zip(list, num):
        str = '\nSize %d * %d'%(i[0], z)
        print(str)
        for j in range(1, len(i), 2):
            str = '%20s %X'%(i[j], i[j+1])
            print(str)

displayResult(list_diff,      list_diff_num)
displayResult(list_noneExist, list_noneExist_num)

解析结果

len 250 250
diff      21 size [77, 17, -1, 73, 14, 7, -1, 1, -1, -1, 73, 46, 7, 8, 77, 15, 25, 14, 17, 1, -1]
noneExist 1 size [[64, 'b.so', 3609046558, 'a.so', 3609290044, 'a.so', 3609286868]]

Size 921600 * 77
       a.so F150
       a.so EFB2
      c.so 2A45E
      c.so 2A61A
      c.so 27E1C
      c.so 27CE8
      c.so 27E68

Size 921600 * 17
       a.so F150
       a.so EFB2
      c.so 2789A
      c.so 2C0D2
      c.so 272EC
      c.so 2E666
      c.so 484CA

Size 176 * -1
      d.so 9186
      d.so 4EE0
      c.so 484E0

出现问题

  • 使用addr2line 显示 ??:0
    分析方式,需找到obj/local/armeabi-v7a/*.so文件分析 注意非最终so路径,而是中间路径obj
  • 使用readelf解析so库
    readelf -a *.so
  • 使用anroid7.0通过HDMI接显示器,start后不能显示,重新插拔HDMI线即可
  • 打开ddms.bat打开失败,没有安装java;
    ddms.bat在android-sdk/tools目录下
  • 编译需要加-g会生成symbols信息在lib中
  • ddms中没有Native Heap
    在ddms.cfg中添加 native=true
    注意写ddms.cfg如果不成功,有可能是权限问题,可以某度查找解决方法

技巧

  • 查找文件
    使用everything检索文件
    这里写图片描述
  • 查看汇编代码
    arm-linux-androideabi-objdump -dS *.so > *.dump
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Native Leak分析 的相关文章

  • Android 动态添加联系表单

    Hi 我想实现如图所示的表单 不知道他们如何动态添加字段 这是列表视图吗 可扩展列表 用户可以在运行时添加和删除 我已经检查了包含子项目的可扩展列表 但我们在数组中定义子元素 在图像中它们动态添加 任何指南 链接 Thanks Custom
  • 图钉的 OnClickListener

    在这里我使用了谷歌地图和叠加层 我使用了图钉图像来指向 GeoPoint 我想设置一个OnClickListener图钉事件 当用户触摸 pin 时 我想吐槽一条消息 下面是代码 import java util List import c
  • 外部硬件指纹扫描仪和 Android 设备集成

    我想建立一个android像员工考勤这样的应用程序使用fingerprint scanner 我想知道 是否可以使用外部硬件设备进行指纹识别 扫描 如何将Android应用程序与外部硬件finger集成 打印扫描设备 如何从外部硬件设备获取
  • android studio 和 android SDK 捆绑的 eclipse 版本有什么区别

    我没有 Android 开发经验 我想开始编写应用程序 The 官方开发者工具页面 http developer android com tools index html包含两个不同 IDE 的链接 第一个包含捆绑的 ADT 版本Eclip
  • 如何在 1 个活动 (android) 中显示 2 个视图?

    假设我打开了一个网络视图 public void onCreate Bundle savedInstanceState super onCreate savedInstanceState setContentView R layout ma
  • kotlin中的三元运算符[重复]

    这个问题在这里已经有答案了 我可以用java写 int i 10 String s i 10 Ten Empty 即使我可以将它传递到方法参数中 callSomeMethod i 10 Ten Empty 如何将其转换为 kotlin 在
  • 安卓多点触控?

    作为一名开发人员 我倾向于先编程 然后再研究 我试图实现一个可以处理多个用户输入的屏幕 基本上映射的不仅仅是一根手指 我尝试了两件事 我有一个实现 OnTouchListener 的 Activity 类 这里我有两个单独的子视图 它们将
  • Android 中未找到 PhoneGap 类错误

    我的 PhoneGap Android 应用程序遇到一些问题 到目前为止我明白了 我已经把一切都做好了 这是我所做的 在 Eclipse 中创建项目后 我在 libs 文件夹中添加了 cordova 2 2 0 jar 然后我编辑了Andr
  • 如何更改所有 ListView 的默认分隔线颜色

    我正在尝试为 style xml 中的所有 listView 应用默认样式 请注意 在某些地方我使用嵌套列表视图 In 样式 xml
  • 我如何将值从基本适配器传递到活动

    我正在一个应用程序中工作 我需要将值从基本适配器类传递到活动 这是片段代码 public View getView int position View convertView ViewGroup parent vi convertView
  • React Native:即使文件不存在,也会出现 hprof 文件太大错误

    当我尝试跑步时git push origin master在我的 React Native 应用程序中 我得到 file android java pid60072 hprof is 564 94 MB this exceeds GitHu
  • 如何让SeekBar占据父级的整个宽度

    我有一个SeekBar in a RelativeLayout其宽度等于屏幕宽度 我申请了layout width match parent to the SeekBar但两边似乎都留有一些空白SeekBar以容纳拇指 我也尝试过使用and
  • 如何使用GDK在卡片上显示静态地图?

    在 Mirror API 中我们可以使用类似的东西 img src height 360 width 240
  • Cordova Android 应用程序中的网页不可用

    编辑 我一直在解决这个问题并回顾我的所有步骤 我很乐意缩小这个问题的规模 并在令人困惑的情况下获得更多确切的细节 目前 我觉得 Keycloak 似乎只想将我重定向到 https 据我所知 这应该是 Wildfly 服务器配置问题 编辑 我
  • android拦截最近的应用程序按钮

    我有一个针对儿童的应用程序 我不希望他们能够单击 最近使用的应用程序 按钮 看起来像两个矩形叠在一起的按钮 我正在负责捕获后退按钮和主页按钮 并且我已经搜索并阅读了很多有关尝试捕获 最近的应用程序 按钮的信息 但大多数人说你不能 或者他们的
  • 处理网络视图中的链接

    我有我的WebView加载网络视图中的所有链接 但是当我选择电子邮件链接时 它会尝试将其加载到网络视图中 而不是在手机上启动电子邮件应用程序 我该如何解决这个问题 链接是mailto 电子邮件受保护 cdn cgi l email prot
  • java.net.ServerSocket.accept () 在 Android 上不返回

    我正在尝试找到一种方法来远程登录到未root的机器人 我有INTERNET权限处于活动状态 我的设备与我的设备连接在同一网络上Mac OS X通过 WiFi 我可以 ping 通我打开的端口 在最初的实验中 我让它在有根测试设备上工作 但我
  • 如何指定使用Glide for Android加载图片的重试次数?

    我正在为我的 Android 应用程序使用 glide 库 我想告诉它在放弃并显示错误占位符图像之前重试获取图像 X 次 可能使用指数退避 知道如何做到这一点吗 顺便说一句 我正在使用 Volley 集成 使用您自己的资源解码器 我仅加载本
  • AS更新到1.0后,项目中出现“method ID not in [0, 0xffff]: 65536”错误

    我将 Android Studio 更新到最新版本 并让它 修复项目 之类的 但现在我的项目无法编译 给了我 FAILED FAILURE Build failed with an exception What went wrong Exe
  • smoothScrollToPosition() 在 Android ICS 中只能滚动到一半?

    在 Gingerbread 中 我使用 smoothScrollToPosition 一次滚动数十个项目没有任何问题 在我的 Nexus S 升级到 Ice Cream Sandwich 后 我注意到无论我在 smoothScrollToP

随机推荐

  • pageHelper分页插件实现原理及使用方法

    插件官方网站 xff1a https github com pagehelper Mybatis PageHelper tree master src main java com github pagehelper 实现原理 xff1a 使
  • 虚拟机Linux系统安装nginx服务器并启动的步骤

    工作前的准备 xff1a 1 装有Linux的虚拟机 2 nginx安装包 xff0c 注意是gz结尾的压缩文件 具体步骤1 xff1a 1 nginx安装环境 nginx是 C 语言开发 xff0c 建议在 linux 上运行 xff0c
  • 什么是反射机制,有什么作用

    1 反射机制定义 反射的概念是由Smith在1982年首次提出的 xff0c 主要是指程序可以访问 检测和修改其本身状态或行为的一种能力 在Java环境中 xff0c 反射机制允许程序在执行时获取某个类自身的定义信息 xff0c 例如熟悉和
  • 模块化建立项目流程(Maven聚合模块)

    先说项目使用Maven的好处 1 项目构建 Maven定义了软件开发的整套流程体系 xff0c 并进行了封装 xff0c 开发人员只需要指定项目的构建流程 xff0c 无需针对每个流程编写自己的构建脚本 2 依赖管理 除了项目构建 xff0
  • 如何在linux下判断web服务是否开启?

    对于web服务的开启的判断有以下几种常用方法 xff1a 1 端口查看 xff1a 本地 xff1a ss xff0c netstat xff0c lsof 1 2 3 4 5 6 7 8 9 10
  • git基本命令

    最近再写一些项目上传到github xff0c 所以要用到git命令 本地需要先安装git客户端 xff0c 然后指定一个git地址为本地仓库 然后右键git bash here打开git命令界面 首先服务端需要创建一个项目以便clone到
  • jps查看Java线程,jstack查看具体线程堆状态

    想要使用jps需要配置环境变量 xff0c 在classpath后在加一个指定Java bin目录 具体命令如下 t2挂起了 xff0c 堆里面显示t2为RUNNABLE xff0c suspend xff0c resume废弃使用 IBM
  • python之ssh连接

    paramiko是用python语言写的一个模块 xff0c 遵循SSH2协议 xff0c 支持以加密和认证的方式 xff0c 进行远程服务器的连接 跟常用软件xshell xftp功能一样 xff0c 但是可以连接多台服务器 xff0c
  • 记录一个类加载变量引发的问题

    类加载变量导致的问题 类加载变量导致的问题 类加载变量导致的问题 因为项目需要 xff0c 银行要求使用weblogic部署并且启动所有项目 xff0c 不允许项目单独开服务启动一般都有这样的要求 xff0c 我所在的项目组有两个单独mai
  • lottie库动画方案

    什么是lottie Lottie是一个库 xff0c 可以解析使用AE制作的动画 xff08 需要用bodymovin导出为json格式 xff09 xff0c 支持web ios android和react native 在web侧 xf
  • for 循环嵌套性能的比较

    有人对着汇编语言不够一屑 xff0c 认为那已经是古老的低级语言 xff0c 是当今的非主流语言 xff0c 学了也不知道有什么用 是的 xff0c 我们不得不承认 xff0c 作为一门古老的语言 xff0c 汇编已经完成了历史赋予它的使命
  • Windows PowerShell打开方法与常用命令

    Windows PowerShell 是一种命令行外壳程序和脚本环境 xff0c 使命令行用户和脚本编写者可以利用 NET Framework 的强大功能 本文来介绍一下它的打开方法和常用的命令 启动方式 Win10系统可以在Cortana
  • Python实现微信自动回复

    先安装 itchat requests itchat uos itchat uos主要解决微信提示禁止网页登录导致登录失败的问题 以下有三种可玩方式 xff1a 1 回复好友 源代码如下 xff1a wechat autoreply imp
  • 体验华为操作系统 openEuler 20.03 LTS linux

    安装华为linux openEuler 20 03 LTS 一直在用centos xff0c 但redhat马上不再对其支持更新了 xff0c 刚好华为发行了社区版linux xff08 ps 难道是centos倒下 xff0c 华为ope
  • c++实现的阻塞队列

    阻塞队列 block queue 什么是阻塞队列 xff1a 在多线程编程时当有多个线程访问一个队列时如果队列为空 xff0c 则获取队列中元素的方法就会阻塞 xff0c 直到队列中有元素可以获取 解决的问题 xff1a 队列的线程安全问题
  • kafka生产者客户端架构和处理流程

    Kafka生产者客户端整体架构如图 xff1a 整个生产者客户端主要有两个线程 xff0c 主线程以及Sender线程 Producer在主线程中产生消息 xff0c 然后通过拦截器 xff0c 序列化器 xff0c 分区器之后缓存到消息累
  • 19、常用类——Collections 类

    Collections 类 Collections 则是集合类的一个工具类 帮助类 xff0c 其中提供了一系列静态方法 xff0c 用于对集合中元素进行排序 搜索以及线程安全等各种操作 常用方法 public static lt T ex
  • 【时间规划】C/C++发展之路--读书

    0 xff1a 图书馆的N本C xff0c C 43 43 书 1 xff1a C语言深度解剖 2 xff1a 高质量C 43 43 c编程指南 3 xff1a C 43 43 primer第四版 4 xff1a Windows程序设计 5
  • SpringSecurity(十七)------CSRF

    一 引入 从刚开始学习Spring Security时 xff0c 在配置类中一直存在这样一行代码 xff1a http csrf disable 如果没有这行代码导致用户无法被认证 这行代码的含义是 xff1a 关闭csrf防护 二 什么
  • Android Native Leak分析

    Native Heap 为 Android C 43 43 层 xff08 也为so库 xff09 所分配的内存 问题描述解决方式数据分析 问题解决方法获取数据方法脚本 python3解析结果 出现问题技巧 问题描述 使用dumspsys