android体系稳固性-内存题目分析总结

藏宝库编辑 2024-10-5 18:32:43 60 0 来自 中国
前言

软件版本在拷机(长稳)阶段最容易体系稳固性题目,而且任何卡死/卡顿/瓦解/重启等现场都大概是内存非常导致,从体系工程师角度会碰到各种内存题目,不管是应用挂死,体系挂死,kernel挂死,应用内存走漏,体系内存走漏,kernel内存走漏等都会碰到,偶然办理一个稳固性题目,必要差别的团队开辟人员,且每次挂死缘故原由都不会一样,一百次挂死有一百个缘故原由,导致题目也不好总结,下面也是根据之前碰到过的内存题目情况,做个大概总结,经供参考;
内存非常分类

内存题目主要非两大类, 内存段错误和内存走漏, 这两大类题目又有很多细分场景;java步调内存题目这里不阐明,由于java内存题目有独立的工具和分析方法,我主要照旧做体系内存分析;

1.png linux内存管理

Linux内核并不是将物理内存直接分配给历程,而是采取捏造内存布局。每个历程拥有一个独立的捏造内存空间和内存映射表(page table),捏造内存到物理内存的地址映射关系记录于page table中,当CPU实行指令时,若该指令是从内存中读取或写入数据时,就必要通过MMU(Memory Manage Unit)将内存virtual address更换为physical address。
内存管理太复杂了,一样寻常只有kernel大神才可以写,这里简单记录下,内存分析有须要相识根本的内存管理根本知识。
Linux内存管理
Linux捏造地址空间布局
Memory Management系列文章
段错误定位

模块分类大概缘故原由定位手段app应用Java运行非常,空指针,无效引用,数组越界抓取tombstone大概dropbox日记分析,java步调段错误墓碑日记一样寻常都可以分析出来jni1. java对象已经被采取,jni还在调用java方法失效(生命周期差别步)
2.jni接口方法和java层不对齐,比如jni接口改动,java照旧调用之前接口
3. jni传入错误的参数抓取tombstone,分析捏造机调用栈native历程或库利用未初始化指针,空指针,数组溢出,内存踩踏,栈空间利用完,数据字节不对齐1. 抓取tombstone大概dropbox日记分析堆栈信息,
2. 地址分析法(objdump,addr2line),背面单独阐明,
3.打开debug编译选型,给大概题目的历程和库添加调试符号。kernel空指针,解码非常,wifi驱动非常kernel内存错误检测工具,kernel panic一样寻常会找芯片原厂一起分析硬件wifi信号干扰ddr时钟频率之前碰到过记录下,wifi信号影响了ddr稳固性,导致各种段错误段错误定位流程

1,根据logcat, tombstone大概dropbox,kernel日记等都可以看到段错误发生的堆栈信息,如果是固定位置发生非常,堆栈信息一样寻常就可以定位出错误代码。
2,堆栈错误符合不足,版本发布后体系库都是颠末裁剪的,如果出现段错误符信息很少,无法分析的情况,可以实验利用objdump反汇编定位大概位置,再进一步分析。如果照旧符号不足,必要编译debug版本复习题目,再分析。
3,栈溢出,历程栈溢出,线程栈溢出都大概会出现的,栈溢出通过段错误地址位置(栈空间),以及SEGV_ACCERR错误,再通过log可以很快分析出有栈溢出情况。

  • 其他特殊场景,SIGBUS,SIGFPE,SIGILL,SIGABRT这些错误都是特定情况才会发生,可以根据堆栈信息,大概objdump反编译定位错误代码位置。
5,  内存踩踏,内存踩踏会出现随机段错误的情况,这个情况定位比力贫苦,我这边定位方法是全代码内存查抄(人工+工具)和清除法,网上也有内存踩踏的定位方法,估计都是kernel大神才华利用吧。
6,复杂场景段错误,在快速利用(压力测试,Monkey测试,Fuzzing测试),多线程场景下大概会忽然出现各种段错误, 这个时间可以思量根据场景规避,大概分析多线程场景调整代码逻辑。
7,  Kernel panic,内核段错误空指针,kernel panic本身定位的少,一样寻常会找芯片大概驱动原厂帮助分析,也可以google错误,有些体系原生bug,网上会有修改方法。
objdump示例

//测试代码#include <stdlib.h>#include <sys/types.h>#include <unistd.h>int main(int argc, char*argv[]){    while(fgetc(stdin) == 'q')    {           break;    }       char *p = "1233454";    free(p);}//运行出现段错误--------- beginning of crash01-01 17:41:36.643  6346  6346 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x1b1c003f8 in tid 6346 (malloc_test)01-01 17:41:36.673  6363  6363 I crash_dump64: obtaining output fd from tombstoned01-01 17:41:36.679  1886  1886 I /system/bin/tombstoned: received crash request for pid 634601-01 17:41:36.680  6363  6363 I crash_dump64: performing dump of process 6346 (target tid = 6346)01-01 17:41:36.680  6363  6363 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***01-01 17:41:36.680  6363  6363 F DEBUG   : Build fingerprint: 'HiDPT/Hi3751V811/Hi3751V811:8.0.0//:eng/release-keys'01-01 17:41:36.680  6363  6363 F DEBUG   : Revision: '0'01-01 17:41:36.680  6363  6363 F DEBUG   : ABI: 'arm64'01-01 17:41:36.680  6363  6363 F DEBUG   : pid: 6346, tid: 6346, name: malloc_test  >>> malloc_test <<<01-01 17:41:36.680  6363  6363 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x1b1c003f801-01 17:41:36.680  6363  6363 F DEBUG   :     x0   000000791c627208  x1   00000001b1c7d710  x2   000000791c60d000  x3   000000000000000001-01 17:41:36.680  6363  6363 F DEBUG   :     x4   000000791c6024d8  x5   0000000000000001  x6   2f6d65747379732f  x7   6c6c616d2f6e696201-01 17:41:36.680  6363  6363 F DEBUG   :     x8   00000001b1c00380  x9   0000000000000070  x10  000000000000007d  x11  000000000000000001-01 17:41:36.680  6363  6363 F DEBUG   :     x12  0000007ffd1e3e18  x13  0000007ffd1e3e50  x14  000000000000000d  x15  aaaaaaaaaaaaaaab01-01 17:41:36.680  6363  6363 F DEBUG   :     x16  000000791ccb1cc0  x17  000000791cc50718  x18  00000000a0ff71b5  x19  00000001b1c7d71001-01 17:41:36.680  6363  6363 F DEBUG   :     x20  000000791c627208  x21  000000791c60d000  x22  0000000000000000  x23  000000791ccbc87801-01 17:41:36.680  6363  6363 F DEBUG   :     x24  0000000000000000  x25  0000000000000000  x26  0000000000000000  x27  000000000000000001-01 17:41:36.680  6363  6363 F DEBUG   :     x28  0000000000000000  x29  0000007ffd1e3f40  x30  000000791cc7ad4401-01 17:41:36.680  6363  6363 F DEBUG   :     sp   0000007ffd1e3f10  pc   000000791cc7a7ec  pstate 000000008000000001-01 17:41:36.683  6363  6363 F DEBUG   :01-01 17:41:36.683  6363  6363 F DEBUG   : backtrace:01-01 17:41:36.683  6363  6363 F DEBUG   :     #00 pc 00000000000907ec  /system/lib64/libc.so (ifree+88)01-01 17:41:36.683  6363  6363 F DEBUG   :     #01 pc 0000000000090d40  /system/lib64/libc.so (je_free+120)01-01 17:41:36.683  6363  6363 F DEBUG   :     #02 pc 0000000000000700  /system/bin/malloc_test (main+32)01-01 17:41:36.683  6363  6363 F DEBUG   :     #03 pc 000000000001b66c  /system/lib64/libc.so (__libc_init+88)01-01 17:41:36.683  6363  6363 F DEBUG   :     #04 pc 0000000000000640  /system/bin/malloc_test (do_arm64_start+80)//利用反汇编在步调查找段错误位置。bzl@ubuntu:~/samba/develop$ aarch64-hisiv610-linux-objdump -dS  out/target/product/Hi3751V811/system/bin/malloc_test  | egrep 700700:    97ffffb8     bl    5e0 <free@plt>bzl@ubuntu:~/samba/develop$ aarch64-hisiv610-linux-objdump -dS  out/target/product/Hi3751V811/system/lib64/libc.so  | egrep 907ec   907ec:    f9403d08     ldr    x8, [x8,#120]bzl@ubuntu:~/samba/develop$ aarch64-hisiv610-linux-objdump -dS  out/target/product/Hi3751V811/system/lib64/libc.so  | egrep 90d40   225d0:    7290d40a     movk    w10, #0x86a0   235a4:    7290d408     movk    w8, #0x86a0   90d40:    97fffe95     bl    90794 <ifree>   90d7c:    17fffff1     b    90d40 <je_free+0x78>bzl@ubuntu:~/samba/develop$内存踩踏举例

I/DEBUG   (  885): Build fingerprint: 'full_godbox/godbox:4.0.3/Sbox8040/80163107:eng/ test-keys'I/DEBUG   (  885): pid: 12736, tid: 13016  >>> net.xxx.app.xx.xx <<<I/DEBUG   (  885): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 68fb2000I/DEBUG   (  885):  r0 68fb2000  r1 010aa470  r2 000013c0  r3 00000000I/DEBUG   (  885):  r4 00000000  r5 00000000  r6 00000000  r7 00000000I/DEBUG   (  885):  r8 00000000  r9 00000000  10 00000000  fp 00000000I/DEBUG   (  885):  ip 010aa4a0  sp 65f5b1d0  lr 40696094  pc 4004ebac  cpsr 20000010I/DEBUG   (  885):  d0  449ed0004432aa00  d1  000004f600000000I/DEBUG   (  885):  d2  44340000000002d0  d3  3ffc71c720000000I/DEBUG   (  885):  d4  4434000000000000  d5  44a0000000000000I/DEBUG   (  885):  d6  3f00000000000000  d7  3ecccccd3f000000I/DEBUG   (  885):  d8  0000000000000000  d9  0000000000000500I/DEBUG   (  885):  d10 0000000000000000  d11 0000000000000000I/DEBUG   (  885):  d12 0000000000000000  d13 0000000000000000I/DEBUG   (  885):  d14 0000000000000000  d15 0000000000000000I/DEBUG   (  885):  scr 20000012I/DEBUG   (  885): D/dalvikvm(12736): GC_CONCURRENT freed 114K, 7% free 10218K/10951K, paused 3ms+16msI/DEBUG   (  885):          #00  pc 0000dbac  /system/lib/libc.so (memcpy)I/DEBUG   (  885):          #01  pc 00067090  /system/lib/libskia.so (_ZN23SkARGB32_Shader_Blitter5blitHEiii)I/DEBUG   (  885):          #02  pc 00061458  /system/lib/libskia.so (_ZN9SkBlitter8blitRectEiiii)I/DEBUG   (  885):          #03  pc 00094128  /system/lib/libskia.soI/DEBUG   (  885):          #04  pc 000941e0  /system/lib/libskia.soI/DEBUG   (  885):          #05  pc 0009428c  /system/lib/libskia.soI/DEBUG   (  885):          #06  pc 00094a54  /system/lib/libskia.so (_ZN6SkScan12AntiFillRectERK6SkRectPK8SkRegionP9SkBlitter)//终极通过规避办理,这个题目是用户快速利用遥控器利用,我们应用在init过程中,被逼迫退出,来回快速利用导致。线程栈空间利用完

如果线程中变量总大小超出栈大小,如果线程中利用了超出栈的以外变量,就会报signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr错误信息,
别的在Android中,线程的栈被是受掩护的,默认设定为mprotect(stack, thread->attr.guard_size, PROT_NONE),不可被读写的,以是会表现如图,如果变量做修改的const变量,则会表现是可读的。
以是,如果libiptvmw.so出现如有莫名其妙的题目,如果有类似的信息,则会由此缘故原由造成的。为了安全起见,发起把 libiptvmw.so中的全部线程的栈大小,都应该调大些。

2.png 音频解码导致踩内存

题目形貌:
机顶盒播放VMX加扰流, 播放一段时间后盒子就挂掉。
题目缘故原由:

  • VMX 加扰流在利用AES-128解码的时间利用了PKCS7算法添补数据, 导致解密后的数据不是188对齐。
  • 机顶盒再给TS BUF送数据的时间会做0x47开头和188字节对齐判断, 如果不是0x47开头就会在拼装188字节的时间丢的一部分数据。
  • 丢掉一部分数据送给TS BUF后, 就会导致AAC播放挂掉。
    验证是AAC题目测试:
  • 我们去掉AAC解码库,播放很久没有死机。
  • 厥后找到缘故原由后,我们把送给TS BUF之前的数据生存下来(就是有丢包的数据),然后用sample_tsplay播放, 发现每次都能死机。
总结:
如果由于丢包导致AAC库内存溢出, 那如果网络非常的时间也有大概会导致挂掉题目, 全部还必要你们进一步定位。
内存走漏分析--传统方法

之前写linux c步调,都是本身打桩linux 步调打桩,core文件, 大概在C内里添加打桩分析内存非常,这个方法背面在android native分析也挺顺应,如今有很多android native定位工具我也没有效过,工具的核心原理和之前用的都差不多;传统方法就是先抓整体内存信息,定位到哪个模块,再抓详细模块内存信息分析;
偶然间内存分析,照旧靠老方法和履历,比如数据库内线走漏,tmpfs走漏,资源走漏等工具就无法分析出来;
抓取内存信息。

#!/system/bin/sh#脚本阐明:抓取体系cpu和内存信息脚本,长稳利用 ,在跑长稳的过程中,#         偶然间logcat日记已经无法满足定位,必要抓取体系的cpu和内存状态信息,才华进一步定位题目。#注意事项:#        1) 由于脚本启动会启动其他厥后下令,如果有利用失误,必要重新抓log,记得先重启机顶盒。#        2)长稳日记,重启不会丢失,但是如果重新抓日记,会删除之前的log, 防止data分区填满。#作者: bzl#开始抓日记时间start_time=$(date +%Y-%m-%d-%H-%M-%S)echo "++++ data_time: ${start_time} \n"#锁定输入,无法相应遥控器echo 1 > /proc/inputblock/status#扫除体系缓存echo 3 > /proc/sys/vm/drop_caches#删除之前的anr, tombstones, log目次rm -rf /data/logrm -rf /data/anr/*rm -rf /data/tombstones/*#重新创建log目次mkdir -p /data/log#抓android的logcat日记logcat -vtime > /data/log/logcat.txt &#抓取体系内核日记cat /proc/kmsg > /data/log/log_kmsg.txt &while truedo{    #记录当前时间cur_time=$(date +%Y-%m-%d-%H-%M-%S)        #抓取top信息, top信息一样寻常包罗cpu的利用率top -m 10 -n 1 >> /data/log/log_top.txtecho "----------${cur_time}-------------\n" >> /data/log/log_top.txt    sleep 1        #抓取用户内存信息    busybox free >> /data/log/log_free.txt    echo "----------${cur_time}-------------\n" >> /data/log/log_free.txt    sleep 1        #抓取详细内存信息    cat /proc/meminfo >> /data/log/log_meminfo.txtecho "----------${cur_time}-------------\n" >> /data/log/log_meminfo.txt    sleep 1        #抓取SDK内存信息。    cat /proc/media-mem >> /data/log/log_media-mem.txtecho "----------${cur_time}-------------\n" >> /data/log/log_media-mem.txt    sleep 1        #抓取当进步程信息    ps >> /data/log/log_ps.txt    echo "----------${cur_time}-------------\n" >> /data/log/log_ps.txt        #抓取芯片温度    cat /proc/msp/pm_cpu >> /data/log/log_pm_cpu.txt    echo "----------${cur_time}-------------\n" >> /data/log/log_pm_cpu.txt    sleep 1        #抓取莫个apk应用内存利用信息,根据实际情况更换包名,下面是卡电的iptv apk应用    #dumpsys meminfo xxxx >> /data/log/log_app_meminfo.txt    #dumpsys meminfo net.xxx.app.youtube >> /data/log/log_app_meminfo.txt    dumpsys meminfo com.huawei.ahdptc >> /data/log/log_app_meminfo.txt    echo "----------${cur_time}-------------\n" >> /data/log/log_app_meminfo.txt    sleep 1        #检察全部历程咱用的内存情况,检察单个历程利用情况可以用procmem pid    procrank -u >> /data/log/log_procrank.txt    echo "----------${cur_time}-------------\n" >> /data/log/log_procrank.txt        #拷贝anr, tombstones日记    cp -rf /data/anr /data/log/    cp -rf /data/tombstones /data/log/        #革新体系缓存,日记文件实时生存到flash上    sync        #就寝时间,    sleep 60 #60s}doneAnroid native内存分析,官网工具

https://developer.android.com/studio/profile/memory-profiler?hl=zh-cn
https://source.android.com/devices/tech/debug/native-memory
Android Native内存分析工具LeakTracer:

https://bbs.huaweicloud.com/blogs/194369
https://blog.csdn.net/SCHOLAR_II/article/details/111930672
https://www.jianshu.com/p/fbc865ea5816
https://www.codeleading.com/article/31113021034/
颠末测试验证:

  • 原始github上LeakTracer,在android上无法跑起来,堆栈记录会段错误,必要unwind方法。网上有人修改针对android的LeakTracer
  • 在32位体系没有题目,在64位体系上有的走漏定位不出来情况。
  • 只能分析库内里的内存走漏,如果是历程内里走漏,堆栈地址信息不对,可以把native服务修改下,把主要函数放到库内里,main只负责拉起来。原始LeakTracer只支持下令,不支持库,颠末修改后的LeakTracer能把库符号打印精确,历程符号就不对了。
Android Native内存分析工具,libc.debug

https://blog.csdn.net/u010481276/article/details/78959368
https://www.daimajiaoliu.com/daima/479ca70349003fc
https://www.cxybb.com/article/xlnaan/84325880
https://www.jianshu.com/p/983728f34f74
https://albuer.github.io/2019/11/30/Android-libc-debug/
Android Native内存分析工具 Raphael

https://mp.weixin.qq.com/s/RF3m9_v5bYTYbwY-d1RloQ
https://jishuin.proginn.com/p/763bfbd6979d
参考文档

应用稳固性优化系列(一),ANR题目全面剖析
应用稳固性优化系列(二),Crash/Tombstone题目分析及定位
应用稳固性优化系列(三),资源走漏题目分析及定位
Android Log的分布、网络、整理
Android中native历程内存走漏的调试本事(一)-- libc debug
利用objdump举行Android crash 日记 分析
android objdump 用法,【转】 Android调试的必杀技——反汇编
Linux情况下段错误的产生缘故原由及调试方法小结
Android非常分析
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2024-11-22 01:22, Processed in 0.184581 second(s), 36 queries.© 2003-2025 cbk Team.

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