-c 统计每一系统调用的所执行的时间,次数和出错的次数等. -d 输出strace关于标准错误的调试信息. -f 跟踪由fork调用所产生的子进程. -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号. -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪. -h 输出简要的帮助信息. -i 输出系统调用的入口指针. -q 禁止输出关于脱离的消息. -r 打印出相对时间关于,,每一个系统调用. -t 在输出中的每一行前加上时间信息. -tt 在输出中的每一行前加上时间信息,微秒级. -ttt 微秒级输出,以秒了表示时间. -T 显示每一调用所耗的时间. -v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出. -V 输出strace的版本信息. -x 以十六进制形式输出非标准字符串 -xx 所有字符串以十六进制形式输出. -a column 设置返回值的输出位置.默认 为40. -e expr 指定一个表达式,用来控制如何跟踪.格式如下: [qualifier=][!]value1[,value2]... qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如: -eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none. 注意有些shell使用!来执行历史记录里的命令,所以要使用\\. -e trace=set 只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all. -e trace=file 只跟踪有关文件操作的系统调用. -e trace=process 只跟踪有关进程控制的系统调用. -e trace=network 跟踪与网络有关的所有系统调用. -e strace=signal 跟踪所有与系统信号有关的 系统调用 -e trace=ipc 跟踪所有与进程通讯有关的系统调用 -e abbrev=set 设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all. -e raw=set 将指 定的系统调用的参数以十六进制显示. -e signal=set 指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号. -e read=set 输出从指定文件中读出 的数据.例如: -e read=3,5 -e write=set 输出写入到指定文件中的数据. -o filename 将strace的输出写入文件filename -p pid 跟踪指定的进程pid. -s strsize 指定输出的字符串的最大长度.默认为32.文件名一直全部输出. -u username 以username 的UID和GID执行被跟踪的命令
centos系统: yum install glibc-utils
mtrace ()开启内存使用记录,muntrace()用于取消内存使用记录。内存使用情况记录到一个文件,值由环境变量:MALLOC_TRACE决定。
编译源文件:gcc -g -DDEBUG testmtrace.c
执行:./a.out 产生mtrace.log
分析结果: mtrace ./a.out mtrace.log
[root@v68869 ~]# mtrace ./a.out mtrace.log - 0x0000000001d04010 Free 3 was never alloc'd 0x7fcd53db596a - 0x0000000001d040f0 Free 4 was never alloc'd 0x7fcd53e771fd - 0x0000000001d04110 Free 5 was never alloc'd 0x7fcd53eeb9dc Memory not freed: ----------------- Address Size Caller 0x0000000001d04590 0x8 at /root/testmtrace.c:19mtrace 采用 malloc_hook + return_addr 这两个机制来实现的
mtrace 会记录所有的分配、释放,包括所有的模块、线程。内存使用记录必将很多,所以官方推荐使用 SIGUSR1或SIGUSR2 来进行开启和关闭内存记录功能。从 mtrace 记录和分析结果可以看到,内存记录日志只记录到 malloc 层面。而实际项目开发时,很多接口都是封装多层才会实际调用到 malloc,对于上面几层的地址,mtrace 没有记录。而上面几层的调用关系才是追踪内存泄漏问题的关键所在。所以在实际开发的项目中,使用 mtrace 不是一个特别好的方法。这里推荐使用 valgrind 工具进行跑流程的方式追踪内存泄漏。如果想要自己记录内存使用情况,可以考虑以下两种方式: 封装一层内存分配、释放的接口函数来记录内存使用情况。项目开发时,统一使用这个接口来进行内存管理。适用于项目尚未开始。使用 malloc_hook 的方式进行记录,项目代码可以不变。适合于项目已经比较庞大了。
ltrace 在某些方面和是trace功能类似
语法:ltrace [option ...] [command [arg ...]]
Usage: ltrace [option ...] [command [arg ...]] Trace library calls of a given program. -a, --align=COLUMN align return values in a secific column. -c count time and calls, and report a summary on exit. -C, --demangle decode low-level symbol names into user-level names. -d, --debug print debugging info. --dl show calls to symbols in dlopened libraries. -e expr modify which events to trace. -f follow forks. -h, --help display this help and exit. -i print instruction pointer at time of library call. -l, --library=FILE print library calls from this library only. -L do NOT display library calls. -n, --indent=NR indent output by NR spaces for each call level nesting. -o, --output=FILE write the trace output to that file. -p PID attach to the process with the process ID pid. -r print relative timestamps. -s STRLEN specify the maximum string size to print. -S display system calls. -t, -tt, -ttt print absolute timestamps. -T show the time spent inside each call. -u USERNAME run command with the userid, groupid of username. -V, --version output version information and exit. -x NAME treat the global NAME like a library subroutine. [root@bogon bin]# ltrace ./cli (0, 0, 0x1321000, -1, 0x1f25bc2) = 0x3c9ba22160 __libc_start_main(0x462ba0, 1, 0x7fff89be1e08, 0x4c6450, 0x4c6440 <unfinished ...> pthread_spin_init(0x7bf600, 0, 0x7fff89be1e18, 8, 0x3c9bf8fba0) = 0 __cxa_atexit(0x4afff0, 0, 0x4c6548, 8, 0x3c9bf8fba0) = 0 __cxa_atexit(0x4a7550, 0, 0x4c6548, 9, 0x3c9bf8fba0) = 0 __cxa_atexit(0x4a7520, 0, 0x4c6548, 10, 0x3c9bf8fba0) = 0 pthread_spin_init(0x7c17e0, 0, 0, 11, 0x3c9bf8fba0) = 0 __cxa_atexit(0x4a2c80, 0, 0x4c6548, 11, 0x3c9bf8fba0) = 0 pthread_spin_init(0x7c18a4, 0, 0, 12, 0x3c9bf8fba0) = 0 __cxa_atexit(0x4a2c70, 0, 0x4c6548, 12, 0x3c9bf8fba0) = 0 strlen("*") = 1 memcpy(0x7c1660, "*", 1) = 0x7c1660 __cxa_atexit(0x481290, 0, 0x4c6548, 42, 0x596b7c) = 0 malloc(72) = 0x1bd9c40 pthread_mutex_lock(0x7bf540, 0x3c9bf8ef60, 0x1bd9c40, 81, 0x3c9bf8e188) = 0 pthread_mutex_unlock(0x7bf540, 0, 0x1bd9c40, 81, 0x7bf540) = 0 pthread_mutex_lock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540) = 0 pthread_mutex_unlock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540) = 0 pthread_spin_init(0x7c1788, 0, 0x7bf540, 0, 0x7bf540) = 0 pthread_mutex_lock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540) = 0 pthread_cond_broadcast(0x7d1920, 0, 0x7bf540, 0, 0x7bf540) = 0 pthread_mutex_unlock(0x7bf540, 1, 0x7bf540, 0, 0x7bf540) = 0 __cxa_atexit(0x47fab0, 0, 0x4c6548, 0, 0x7bf540) = 0 pthread_spin_lock(0x7c1788, 13, 0, 15, 0x3c9bf8fba0) = 0 pthread_spin_unlock(0x7c1788, 13, 0, 15, 0x3c9bf8fba0) = 0 pthread_spin_init(0x7c16e8, 0, 0, 15, 0x3c9bf8fba0) = 0 strlen("C") = 1 memcpy(0x7c16f0, "C", 1) = 0x7c16f0 malloc(216) = 0x1bd9c90