这篇文章主要主要记录下我对 linux 开发板的一些性能工具的使用和各问题定位的学习和应用, 分4大块,基础知识,内存泄露的定位,cpu 性能的定位, 还有 coredump 文件分析。 主要是内存泄露的定位。不过,我觉得在定位这些问题首先应该对相关的代码有一定了解,因为对代码了解可以帮助我们更快的定位问题。
Linux内核内存管理使用 OOM killer(Out-Of-Memory killer)机制,在系统内存不足时,选择性杀死一些进程以释放内存,以使系统继续运行。内核会通过特定的算法给每个进程计算一个分数来决定杀哪个进程,每个进程的 oom 分数可以 /proc/PID/oom_score 中找到。
防止重要的系统进程触发(OOM)机制而被杀死:可以设置参数 /proc/PID/oom_adj 为-17,可临时关闭 linux 内核的 OOM 机制。
理解 glibc malloc
glibc 内存管理机制:为每个程序的每个线程维护一块内存,称为 arena,随着线程的增加会动态的增加 arena 的数量,arena 申请不回收,并且每次申请大块的内存,自己管理,进程释放并不会立马还给系统而是自己管理,只有当堆顶的内存大于 M_TRIM_THRESHOLD 的值 glibc 才会真正的还给系统。
建议:
https://www.cnblogs.com/DswCnblog/p/5780389.html
linux 常用的基础工具有 nm,readlf,file,
gdb,gdbserver,strace,pstrace
1. 在设备端运行 gdbserver,并 attach 到调试进程(ip是设备ip)
gdbserver IP:PORT --attach ${pid}
2. 在 pc 端运行 gdb
target remote IP:PORT
file+测试进程
set sysroot+带符号表的动态库
3. 进行 gdb 调试
查看进程或者线程当前的系统调用
strace -p ${pid}/${tid}
1.指定具体开发板使用的编译工具链
export PATH=$PATH:/home/hang/work/test/thub/openwrt/staging_dir/toolchain-aarch64-linux-gnu/bin
export CROSS_COMPILE = aarch64-linux-gnu-
export CC = ${CROSS_COMPILE}gcc
export CPP = ${CROSS_COMPILE}cpp
export CXX=${CROSS_COMPILE}g++
export LD = ${CROSS_COMPILE}ld
export AR = ${CROSS_COMPILE}ar
2. 下载编译对应的工具
cat /proc/${pid}/status
cat /proc/${pid}/smaps
申请
mmap :申请虚拟内存地址空间,当实际读写时,由page_fault中断将空闲的物理内存页映射到虚拟内存地址。
brk : 边界下移时申请内存。
释放
munmap:释放虚拟地址空间,同时释放物理内存
brk: 边界上移时释放内存
madvise(…, MADV_DONTNEED):仅释放物理内存,同时适用于mmap或brk申请的内存
示例
heap check :
LD_PRELOAD=/tmp/libtcmalloc.so.4.5.3 env HEAPCHECK=as-is HEAP_CHECK_IGNORE_THREAD_LIVE=false HEAP_CHECK_DUMP_DIRECTORY=/data/ /usr/bin/iotjs /usr/yoda/services/multimediad/index.js
heap profile :
1.
//注:Dump heap profiling information whenever the high-water memory usage mark increases by the specified number of bytes.
export HEAP_PROFILE_INUSE_INTERVAL=3145728
//注:Dump heap profiling information whenever the specified signal is sent to the process.
export HEAPPROFILESIGNAL=12
//注:Profile mmap, mremap and sbrk calls in addition to malloc, calloc, realloc, and new. NOTE: this causes the profiler to profile calls internal to tcmalloc, since tcmalloc and friends use mmap and sbrk internally for allocations. One partial solution is to filter these allocations out when running pprof, with something like pprof --ignore='DoAllocWithArena|SbrkSysAllocator::Alloc|MmapSysAllocator::Alloc.
export HEAP_PROFILE_MMAP=1
export HEAPPROFILE=/data/tcmalloc.log
LD_PRELOAD=/data/lib/libtcmalloc.so.4.5.3
2. 重启程序
产生 dump 文件 ,在 pc 上使用 pprof 做 diff
pprof --text --lib_prefix=pc上带符号表的库 --base=tcmalloc.log.0001.heap ./bin/test(注:pc上对应的dump 进程) tcmalloc.log.0002.heap --stack
示例
VALGRIND_LIB=/data//lib/valgrind/ valgrind --log-file=/data/val.log --error-limit=no --leak-check=full --show-leak-kinds=all /data/rplayer_demo https://rokidstorycdn.rokid.com/story/track/9677547/wKgDZ1Y4GyqTMGYYAC-S81q-PzI118.mp3
注意
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$pwd
一个应用占用 CPU 很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。
1.查看进程中的哪个线程cpu的占用率高
top -Hp ${pid}
2. 如果对代码很熟悉,可以直接使用 strace 查看线程当前的系统调用
注:tid 是通过 1 查看对高 cpu 的线程 id
strace -p ${tid}
否则就使用 adbserver attach 进程查看cpu高的线程的堆栈调用
1.gdb+ 程序+ core文件
2.file+程序
3. info share (查看动态库)
4. 没有动态库的话加载动态库
set solib-search-path + 库的路径
5.查看coredump 时的栈信息
bt 或者 where
https://blog.csdn.net/u014403008/article/details/54666438
使用的是网页版的 gdb( 有兴趣可以看看网页版gdb的实现 https://www.youtube.com/watch?v=OyWaAJD6hr8 )