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

这篇具有很好参考价值的文章主要介绍了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库,因此将这个标准库放入即可。如下图
android 如何分析应用的内存(九)——libc回调,android  内存分析,Android 内存分析,Android libc回调,get_malloc_leak,free_malloc_lea,malloc info

然后将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。如下图
android 如何分析应用的内存(九)——libc回调,android  内存分析,Android 内存分析,Android libc回调,get_malloc_leak,free_malloc_lea,malloc info

android 如何分析应用的内存(九)——libc回调,android  内存分析,Android 内存分析,Android libc回调,get_malloc_leak,free_malloc_lea,malloc info

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

android 如何分析应用的内存(九)——libc回调,android  内存分析,Android 内存分析,Android libc回调,get_malloc_leak,free_malloc_lea,malloc info

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

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

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

至此,libc回调介绍完毕。

除了通过libc回调收集内存分配信息以外,还可以通过malloc info收集以及libmemunreachable收集,将会在下一小节中介绍文章来源地址https://www.toymoban.com/news/detail-518220.html

到了这里,关于android 如何分析应用的内存(九)——libc回调的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • android 如何分析应用的内存(十一)——ASan

    接下来是,heap的第五大板块——ASan(Address Sanitizer)和HWASan(Hardware Address Sanitizer)。可以将其称为:地址清理器 与其说是Heap板块,不如说是debug板块。 ASan是一个集成在编译器中的工具,因此只需要在编译的时候设置好Flag即可。而HWASan则可以认为是ASan的plus版本。HWASan比

    2024年02月13日
    浏览(39)
  • android 如何分析应用的内存(十三)——perfetto

    本篇文章是native内存的最后一篇文章——perfetto 从2018年始,android开发者峰会正式推出perfetto工具。从此perfetto成为安卓最重要的工具之一。在2018年以前,android使用systrace工具,进行同样的工作。 perfetto分成三部分: 第一部分: 录制。这部分将录制不同的数据来源,如:内存,

    2024年02月09日
    浏览(40)
  • android 如何分析应用的内存(八)——Android 7.0以后的malloc debug

    接上文,介绍六大板块中的第三个————malloc调试和libc回调 上一篇文章中,仅仅是在分配和释放的时候,拦截对应的操作。而不能进一步的去检查内存问题。比如:释放之后再次使用指针,内存泄漏,内存损坏等等。 在这篇文章中,将会介绍malloc调试技术,它可以对nat

    2024年02月10日
    浏览(45)
  • Android应用开发-Flutter的LongPressDraggable控件回调函数onDraggableCanceled使用

    以下是如何使用 onDraggableCanceled 的示例: velocity 参数表示拖动被取消时的速度信息。 offset 参数表示拖动被取消时的偏移量信息。 这个回调通常用于在拖动被取消时执行一些清理工作或展示一些反馈。例如,你可能想要将拖动对象返回到原始位置,或者显示一个提示,告诉用

    2024年03月08日
    浏览(42)
  • 如何使用KoodousFinder搜索和分析Android应用程序中的安全威胁

    KoodousFinder是一款功能强大的Android应用程序安全工具,在该工具的帮助下,广大研究人员可以轻松对目标Android应用程序执行安全研究和分析任务,并寻找出目标应用程序中潜在的安全威胁和安全漏洞。 在使用该工具之前,我们首选需要访问该工具的【开发者门户】创建一个

    2024年02月13日
    浏览(64)
  • Android内存泄漏分析及检测工具LeakCanary简介,Android进阶

    @Synchronized override fun expectWeaklyReachable( watchedObject: Any, description: String ) { if (!isEnabled()) { return } removeWeaklyReachableObjects() val key = UUID.randomUUID() .toString() val watchUptimeMillis = clock.uptimeMillis() val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) SharkLog.d { \\\"Watching \\\" +

    2024年04月25日
    浏览(41)
  • Android Profiler 内存分析器使用

    Android Profiler是Android Studio的一部分,提供了一个集成的性能分析工具套件,包括内存分析。Android Profiler 工具可提供实时数据,帮助您了解应用的 CPU、内存、网络和电池资源使用情况。 在Android Profiler中,您可以查看内存使用情况的实时图表、堆转储快照、分析内存泄漏等,

    2024年02月08日
    浏览(53)
  • Android 内存分析(java/native heap内存、虚拟内存、处理器内存 )

    1.jvm 堆内存(dalvik 堆内存) 不同手机中app进程的 jvm 堆内存是不同的,因厂商在出厂设备时会自定义设置其峰值。比如,在Android Studio 创建模拟器时,会设置 jvm heap 默认384m , 如下图所示: 当app 进程中java 层 new 对象(加起来总和)占用的堆内存达到jvm heap 峰值时,就会抛出OOM 。

    2024年02月14日
    浏览(50)
  • Android 内存泄漏、性能分析常用工具

    一、内存泄漏 1、 MAT-eclipse :“Memory Analyzer Tool”,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。 2、Leakcanary :一款开源的自动检测内存泄漏的工具。 3、AndroidStudio Profiler :Android Studio 3.0 采用全新

    2024年02月12日
    浏览(52)
  • 【Android】一个contentResolver引起的内存泄漏问题分析

    长时间的压力测试后,系统发生了重启,报错log如下 JNI ERROR (app bug): global reference table overflow (max=51200) global reference table overflow的log 08-08 04:11:53.052912   973  3243 F zygote64: indirect_reference_table.cc:256] JNI ERROR (app bug): global reference table overflow (max=51200) 08-08 04:11:53.053014   973  3243 F z

    2024年02月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包