android 如何分析应用的内存(九)——libc回调

news2024/9/21 4:26:04

android 如何分析应用的内存(九)

接上文,在前面文章中,介绍了bionic库提供的各种功能,其中包括:

  1. 自定义的malloc
  2. malloc hook
  3. malloc debug

接下来,介绍的是bionic库提供的libc回调功能,它可以通过代码获得所有的内存分配情况 。

libc回调

无论是Android 7.0之前,还是Android 7.0之后,bionic库都提供了一个回调接口,用于获取对应的分配信息。如下:

extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size);

其中,info包含所有的分配信息。overall_size是info的大小。而info_size是表示info中的每个项的大小,如果为0,则表示没有内存被跟踪。total_memory是当前时刻所有已经分配的memory大小,它不会包含libc库自己使用的内存大小。backtrace_size是最大的栈帧数。

info的格式如下:

size_t size_of_original_allocation ## 原始分配的大小,注意,这个数值的31位为1时,表示是从zygote进程的子进程分配的。比如应用程序
size_t num_allocations ## 分配了多少个,即具有相同调用栈和分配大小的个数。在android 7.0时,这个值被错误的设置成了堆栈指针的个数。
uintptr_t pc1 ## 分配时对应堆栈的pc指针
uintptr_t pc2
uintptr_t pc3
.
.
.

有多少个分配,则可以通过overall_size除以info_size获得。pc1,pc2,pc3的个数则由backtrace_size决定。如果堆栈指针个数小于最大值,剩下的位置为0.

注意:对于32位系统,size_t和uintptr_t 都是4个字节。而64位系统则为8个字节

使用完get_malloc_leak_info之后,需要调用

extern "C" void free_malloc_leak_info(uint8_t* info);

将返回的info进行释放。

libc回调举例

首先在必要的位置,声明函数如下:

extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size);
extern "C" void free_malloc_leak_info(uint8_t* info);

然后在必要的地方,调用对应的函数,如下:

uint8_t* info = nullptr;
size_t overall_size = 0;
size_t info_size = 0;
size_t total_memory= 0;
size_t backtrace_size = 0;

get_malloc_leak_info(&info,&overall_size,&info_size,&total_memory,&backtrace_size);

需要注意的是,上面两个函数的定义在libc库中,因此在编译的时候,需要链接libc库。针对Cmake和Android.mk增加如下代码:

## cmake代码
set(LINK_FLAGS    "-lc")
set(CMAKE_SHARED_LINKER_FLAGS "${LINK_FLAGS}")
## makefile代码
LOCAL_LDLIBS            := -lc

在运行的时候,可能提示,没有libc++_shared.so库,因此将这个标准库放入即可。如下图
在这里插入图片描述

然后将info中的数据输出。如下:

ALOGD("overall_size %zu info_size %zu",overall_size,info_size);
for(size_t i=0;i<overall_size/info_size ;i++){
	//获取第i个分配项
    auto buffer = info + info_size*i;
    //获取正确的大小,处理掉第31位
    auto size = *(size_t *)buffer & ~(0x1 << 31);
    ALOGD("#-------这是第%zu个分配,原始分配大小%zu,分配个数%zu",i,size,*(size_t *)(buffer+sizeof(size_t)));
    //获取堆栈头指针
    auto pc = (uintptr_t *)(buffer+sizeof(size_t)*2);
    //定义一个缓存位置,并初始化
    char out[1024*backtrace_size];
    for(size_t l=0;l<1024*backtrace_size;++l){
        out[l] = '\0';
    }
    //解析堆栈指针,并将解析结果放入out中
    dumpBacktraceIndex(out,(intptr_t *)pc,backtrace_size);
    //输出解析结果到log中
    std::ostringstream tempString;
    for(size_t k = 0;k<1024*backtrace_size;k++){
        if(out[k] != '$'){
            tempString << out[k];
        }else{
            ALOGD("%s",tempString.str().c_str());
            tempString.str("");
            tempString.clear();
        }
    }
    ALOGD("#-------这是第%zu个分配,完成",i);
}

其中,dumpBacktraceIndex函数,即我们在
android 如何分析应用的内存(六)——自定义malloc中提及的Debug类中的函数。

如下:

void dumpBacktraceIndex(char *out, intptr_t *buffer, size_t count) {
    for (size_t idx = 0; idx < count; ++idx) {
        intptr_t addr = buffer[idx];
        const char *symbol = "      ";
        const char *dlfile = "      ";
        void * baseA = NULL;
        char temp[50];


        Dl_info info;
        info.dli_fbase = NULL;
        if (dladdr((void *) addr, &info)) {
            if (info.dli_sname) {
                symbol = info.dli_sname;
            }
            if (info.dli_fname) {
                dlfile = info.dli_fname;
            }
            if(info.dli_fbase){
                baseA = info.dli_fbase;
            }

        } else {
            strcat(out, "#                          ");
            strcat(out,"$");
            continue;
        }

        memset(temp, 0, sizeof(temp));
        sprintf(temp, "%zu", idx);
        strcat(out, "#");
        strcat(out, temp);
        strcat(out, ": ");
        memset(temp, 0, sizeof(temp));
        sprintf(temp, "%p", (void *) addr);
        strcat(out, temp);
        strcat(out, "  ");
        memset(temp, 0, sizeof(temp));
        sprintf(temp, "%p", (void *) ((long)addr -  (long )baseA));
        strcat(out, temp);
        strcat(out, "  ");
        strcat(out, symbol);
        strcat(out, "      ");
        strcat(out, dlfile);
        strcat(out, "$");
    }
}

libc回调举例

为了测试libc是否能够正常工作,在适当的地方故意做如下操作:

auto *p = new int[41024*4];
p[1] = 12354;
auto *p1 = new int;
*p1 = 2345678;

然后触发libc回调,得到如下的log。如下图
在这里插入图片描述

在这里插入图片描述

除此之外,还能看到其他的分配,如下图

在这里插入图片描述

实际使用中,可通过监控total_memory来判断是否存在内存泄漏。然后再分析info中的所有分配,来查看具体的泄漏点。同时,可以对分配的数据,进行大小排序,而达到查看的目的。

事实上,部分Android的内存分析工具,就是通过libc回调实现的。

注意:上诉所有例子,都是在Android 8.1上测试。同时,存在部分国内的Android版本,无法使用malloc调试和libc回调。此时,若要进行内存分析,可更换Android 设备。

至此,libc回调介绍完毕。

除了通过libc回调收集内存分配信息以外,还可以通过malloc info收集以及libmemunreachable收集,将会在下一小节中介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/698081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java】Java核心 77:Dom4j 解析 XML综合案例

文章目录 1、需求2、案例效果3、案例分析4、自定义JDBC框架-代码实现4.1、Configuration4.2、注解4.3、映射类&#xff1a;Mapper4.4、SqlSession类 5、自定义JDBC框架的使用5.1、数据表5.2、创建实体类5.3、UserMapper接口5.4、配置文件&#xff1a;config.xml5.5、测试类5.5、…

当金融风控遇上人工智能,众安金融的实时特征平台实践

导读&#xff1a;随着企业数字化转型升级&#xff0c;线上业务呈现多场景、多渠道、多元化的特征。数据要素价值的挖掘可谓分秒必争&#xff0c;业务也对数据的时效性和灵活性提出了更高的要求。在庞大分散、高并发的数据来源背景下&#xff0c;数据的实时处理能力成为企业提升…

vCenter崩了之后重新搭建处理办法

一、需要重新搭的情况下&#xff0c;vCenter虚拟机是无法使用分布式端口组的&#xff0c;而此时所有的物理网卡都在分布式交换机上&#xff0c;这样vCenter虚拟机的网络是无法访问的&#xff0c;所以需要先找到需要一台esxi。 二、此时可以看到两个分布式交换机 正常情况下分布…

高性能商品秒杀抢购系统

完整资料进入【数字空间】查看——baidu搜索"writebug" Goirisrabbbitmqmysql构建高性能商品秒杀抢购系统 一、项目介绍 1. 课程目标 应用GoWeb快速构建秒杀系统全流程应用开发及架构化设计思维梳理逐级优化&#xff0c;轻松应对“秒杀”及类似高并发场景 2. 知…

layui框架学习(30:树形模块)

Layui中的树形组件模块tree用于以树形形式显示上下级结构的数据&#xff0c;类似于winform中的tree控件。tree模块的基本用法及显示效果如下所示&#xff1a; <div id"test"></div><br /><script>layui.use([tree,layer], function(){var tr…

python安装pyelliptic-.5.7报错ImportError: No module named setuptools

1.背景&#xff1a; python安装pyelliptic-.5.7模块报错 2.环境及版本&#xff1a; linux&#xff1a;centos-7.7 python&#xff1a; 2.7.5 pyelliptic&#xff1a;5.7 注意&#xff1a;这里是纯内网环境所以pip不能使用&#xff0c;我这里配置了一个内部yum源 3.解决思路&…

Spring Boot 中的事务注解

在应用程序中&#xff0c;事务管理是一个非常重要的概念。事务是指一系列的操作&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败。在Spring Boot中&#xff0c;可以使用事务注解来管理事务。在使用事务注解的时候&#xff0c;一个非常重要的概念就是事务传播行为。 …

js内存泄漏及排查详解

js内存泄漏及排查详解 常见内存泄漏及解决方案 内存泄漏&#xff08;Memory Leak&#xff09;是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放&#xff0c;造成系统内存的浪费&#xff0c;导致程序运行速度减慢甚至系统崩溃等严重后果。 隐式全局变量 在局部…

音频小说项目介绍

看小说、听音频&#xff0c;App,H5网站&#xff0c;小程序多端开发 一、主页 主页tabBar四个分类&#xff1a; 首页&#xff0c;分类&#xff0c;收藏&#xff0c;我的 最上方是搜索框 下方是轮播图&#xff0c;不但自动滚动&#xff0c;还有动画效果 下面分类有&#xf…

IDEA 或者SVN修改老项目的svn地址

公司svn地址修改了&#xff0c;ip修改了。本地还有代码没提交。这里介绍一下怎么在IDEA或svn修改为新地址&#xff0c;然后代码就可以直接提交了。网上也有文章介绍&#xff0c;但其中没注明一个关键点&#xff0c;导致很多人修改不成功。所以有了这篇文章。 IDEA下修改svn地址…

【Python】模块导入 ⑤ ( 主程序判断语句 | 模块中执行函数问题 | 制作自定义模块并执行函数 | 导入自定义模块会执行模块中的代码 )

文章目录 一、模块中执行函数问题1、制作自定义模块并执行函数2、导入自定义模块会执行模块中的代码3、主程序判断语句4、代码示例 - 主程序判断语句 一、模块中执行函数问题 1、制作自定义模块并执行函数 如果在自定义模块中 , 定义了函数 , 并且调用了该函数 ; 如下代码所示…

【TCP/IP】多播 - 定义、原理及编程实现 (TTL、多播组、多播消息)

目录 多播 多播的原理 多播的数据传输时的特点 TTL 的概念 TTL 和 多播组的配置方法 多播的编程与实现 发送者 接收者 多播 多播是一种介于单播和广播通信之间的技术方式&#xff0c;可以将发送者所需要发送的数据包分别发送给分散在不同子网中的一组接收者。 多播的原…

MySQL - 第11节 - MySQL事务管理

1.事务的概念 事务的概念&#xff1a; • 上层看起来比较简单的需求&#xff0c;可能对应的后端要做很多工作&#xff0c;后端这些工作组合起来才是一个完整的需求解决的方案。 • 事务由一条或多条SQL语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;共同完成一个…

聊聊transformers库; 微软推出ZeRO++技术:优化大型AI模型训练时间和成本

&#x1f989; AI新闻 &#x1f680; 微软推出ZeRO技术&#xff1a;优化大型AI模型训练时间和成本 摘要&#xff1a;据报道&#xff0c;微软研究人员最近发布了一项名为ZeRO的新技术&#xff0c;旨在优化训练大型AI模型时常遇到的数据传输成本和带宽限制问题&#xff0c;可大…

【0212】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13 - 2)

文章目录 1. 回顾2. 密码校验通过3. 密码校验失败上一文:【0211】tcpdump抓包分析pg_hba.conf以password作为认证证方式下frontend与Backend之间身份验证过程(13 - 1) 1. 回顾 在上一节内容中,讲解了Backend对于接收到来自frontend的字符串明文密码,和来自于来自pg_auth…

荷兰宽带数据泄露 1

又要引入一个新工具RouterPassView 大多数现代路由器都可以备份一个路由器的配置文件&#xff0c;然后在需要的时候从文件中恢复配置。路由器的备份文件通常包含了像您的ISP的用户名重要数据/密码&#xff0c;路由器的登录密码&#xff0c;无线网络的KEY。 如果你忘记了这些密码…

第八十九天学习记录:C++核心:引用

引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名原名 #include<iostream> using namespace std;int main() {//引用基本语法//数据类型 &别名 原名int num1 3;int &num2 num1;cout << "num1" << n…

输入路由器IP地址进入IIS问题解决

0x01 问题描述 Windows10系统&#xff0c;路由器IP为192.168.1.1&#xff0c;本机获取的IP为192.168.1.110&#xff0c;但在浏览器URL输入路由器IP时却没有进入路由登录页&#xff0c;而是进了IIS欢迎页面。 0x02 问题分析 由于我本机IP不是192.168.1.1&#xff0c;所以排除与…

第八十七天学习记录:Linux基础:基础指令Ⅱ

touch创建文件 可以通过touch命令创建文件 语法&#xff1a;touch Linux路径 1、touch命令无选项&#xff0c;参数必填&#xff0c;表示要创建的文件路径&#xff0c;相对、绝对、特殊路径符均可以使用 cat命令 查看文件内容 首先用Vim编辑器在刚刚新建的tanktest.txt中编辑…

MyBatis学习笔记--中篇

MyBatis学习 文章目录 MyBatis学习1、MyBatis 配置解析1.1、核心配置文件1.2、事务管理器&#xff08;transactionManager&#xff09;1.3、数据源&#xff08;DataSource&#xff09;1.4、属性&#xff08;properties&#xff09;1.5、类型别名&#xff08;typeAliases&#x…