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

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

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

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

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

前情提要:在使用libc回调的时候,依然需要打开malloc的调试功能,见上一篇文章中的如何启用malloc debug
android 如何分析应用的内存(八)

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.hqwc.cn/news/1341.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker学习笔记7

启动一个运行httpd服务的容器&#xff1a; docker run -it --namec3 centos:latest /bin/bash 在容器中安装apache服务&#xff1a; yum install -y httpd 在这个过程中遇到一个问题&#xff1a; Error: Failed to download metadata for repo appstream: Cannot prepare …

【Vue】axios发请求下载excel--20230630

1.关键点&#xff1a; blob乱码传参 2.参考资料&#xff1a;处理blob文件流和乱码问题 https://blog.csdn.net/qq_41512902/article/details/125680531 https://blog.csdn.net/qq_38804584/article/details/109238794 3.我的代码&#xff1a;axios发请求下载excel js代…

python 深度学习 解决遇到的报错问题

目录 一、解决报错ModuleNotFoundError: No module named ‘tensorflow.examples 二、解决报错ModuleNotFoundError: No module named ‘tensorflow.contrib‘ 三、安装onnx报错assert CMAKE, ‘Could not find “cmake“ executable!‘ 四、ImportError: cannot import na…

ARM-SWI 和未定义指令异常中断处理程序的返回(七)

文章目录 处理流程示例代码实现SWI未定义指令 附录源码 处理流程 SWI 和未定义指令异常中断是由当前执行的指令自身产生的&#xff0c;当 SWI 和未定义指令异常中断产生时&#xff0c;程序计数器的 PC 的值还未更新&#xff0c;它指向当前指令后面第 2 条指令&#xff08;对于…

【算法题】动态规划中级阶段之最长回文子串、括号生成、跳跃游戏

动态规划中级阶段 前言一、最长回文子串1.1、思路1.2、代码实现 二、括号生成2.1、思路2.2、代码实现 三、跳跃游戏 II3.2、思路3.2、代码实现 总结 前言 动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种解决多阶段决策过程最优化问题的方法。…

香港大学推出创新科技教育基金,拟支持Web3和生成式AI等领域教学

区块链技术是近年来备受关注的领域之一,其应用范围已经涵盖了金融、医疗、物流等众多行业。而随着区块链技术的不断发展和完善&#xff0c;越来越多的企业和机构开始将其应用到实际生产和业务中。作为其中一个重要的应用领域&#xff0c;金融领域也成为了区块链技术的重要应用场…

3-css高级特效-1

01-平面转换 简介 作用&#xff1a;为元素添加动态效果&#xff0c;一般与过渡配合使用 概念&#xff1a;改变盒子在平面内的形态&#xff08;位移、旋转、缩放、倾斜&#xff09; 平面转换也叫 2D 转换&#xff0c;属性是 transform 平移 transform: translate(X轴移动距…

Linux——进程通信之共享内存

目录 一. 回顾上文 二.共享内存 1.定义 2.特点&#xff1a; 3.实现步骤&#xff1a; 如下为成功链接共享内存使用权的完整步骤&#xff1a; 4.函数介绍 4.1shmget函数 4.1.2参数介绍 4.2ftok函数&#xff1a; 4.2.1参数介绍 关于ftok(); shmget();函数的代码实验…

【吃透网络安全】2023软考网络管理员考点网络安全(三)计算机系统安全评估

涉及知识点 计算机系统安全评估准则&#xff0c;计算机系统安全评估历史&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 后面还有更多续篇希望大家能给个赞哈&#xff0c;这边提供个快捷入口&#xff01; 第一节…

Java版工程项目管理系统源码 工程项目源码

数 据 库&#xff1a; MySQL 开发语言&#xff1a; Java 开发工具&#xff1a; MyEclipse 源码类型&#xff1a; WebForm 以甲方项目管理为中心&#xff0c;包括项目启动、计划、执行、控制与收尾阶段的全生命周期管理&#xff0c;并对范围、预…

【数据库课设】图书馆资源管理系统 源码+流程图+结构设计(借还图书 逾期罚款 图书管理 读者管理 信息查询)python实现

文章目录 一 实现功能&#xff08;1&#xff09;管理员功能&#xff08;2&#xff09;读者功能 二 数据流图三 概念结构设计四 文件目录五 源码&#xff1a;main.py六 运行截图 一 实现功能 &#xff08;1&#xff09;管理员功能 一个管理员编号对应一个密码&#xff0c;且需…

drone、gogs、docker与项目集成实现自动化部署

目录 前言项目目录结构目录结构测试文件 文件内容Dockerfilerun.shdrone.yml 测试打包部署中查看容器访问项目成功 常见问题Gogs 推送 URL 被解析到默认禁用的本地网络地址1、drone登录没有权限2、cannot ping the remote server3、推送代码以后不能自动clone4、maven编译报错F…