内存检查工具
Read time: 5 minute(s)
在用户态程序开发过程中,诸如内存泄漏、越界等问题较难定位,使用第三方工具可以提高问题定位效率,如下所示:
名称 | 优点 | 缺点 |
---|---|---|
valgrind | 功能强大。 | 需要使用源码编译;对 RISCV 支持不够好;运行时对性能影响较大。 |
ASAN | 使用简单,只需要添加编译选项。 | Luban 的工具链不支持 ASAN。 |
mtrace | 使用简单,只需增加一个头文件和编译选项。 | 查看结果不方便,需要使用 mtrace 工具转换,Luban 的工具链中没有该工具。 |
memwatch | 使用简单,编译时添加两个文件和编译选项。 | - |
在 Luban 系统中,推荐使用 memwatch。
memwatch
Read time: 5 minute(s)
memwatch 是一个检查内存使用不当等问题的工具,包括检测多次释放、错误释放、内存泄漏、溢出等内存问题。memwatch 的使用说明如下:
- 分别下载 memwatch.c 和 memwatch.h 文件。
- 将下载的两个文件加入测试工程代码并重新编译,且在编译时需添加编译选项 -DMEMWATCH –DMW_STDIO。
- 将编译后的可执行文件和动态库推入板子。
- 按照正常流程运行程序,执行过程中会在当前目录下生成 memwatch.log。
检测内存泄露
以下是检测内存泄露的相关代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memwatch.h"
int main(int argc, char **argv)
{
char *buf1 = (char *)malloc(2048);
memset(buf1, 0, 2048);
char *buf2 = (char *)malloc(2048);
memset(buf2, 0, 2048);
buf2[2052] = 10;
free(buf2);
return 0;
}
详细检测内存泄露的步骤流程如下所示:
- 将上述代码文件和 memwatch.c、memwatch.h
放在一个目录下,执行以下命令进行编译:
gccmemwatch.ctest.c-DMEMWATCH-DMW_STDIO -o test
- 执行
./test
命令。执行上述命令后,会在当前目录下生成 memwatch.log 文件,示例如下,其中第 8 行代码显示申请的内存没有释放,第 15 行代码检测到内存溢出:
============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh ============= Started at Wed Jul 12 11:31:33 2023 Modes: __STDC__ 64-bit mwDWORD==(unsigned int) mwROUNDALLOC==8 sizeof(mwData)==56 mwDataSize==56 overflow: <3> test.c(15), 2048 bytes alloc'd at <2> test.c(11) Stopped at Wed Jul 12 11:31:33 2023 unfreed: <1> test.c(8), 2048 bytes at 0x1d7e640 {00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................} Memory usage statistics (global): N)umber of allocations made: 2 L)argest memory usage : 4096 T)otal of all alloc() calls: 4096 U)nfreed bytes totals : 2048
注意事项
内存越界检查的原理如下:
- 申请内存时,在实际使用内存前后会多分配 8 个字节,并为其赋初值。
- 释放内存时,通过检查多余的几个字节是否为初值来判断是否存在内存越界。
例如,以下示例不能检测到内存越界:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memwatch.h"
int main(int argc, char **argv)
{
char *buf1 = (char *)malloc(2048);
memset(buf1, 0, 2048);
buf1[3000] = 10;
free(buf1);
return 0;
}
valgrind
Read time: 5 minute(s)
valgrind (官网地址:https://valgrind.org)是一个用于内存调试、内存检测以及性能分析的工具集合,包含如下工具:
-
Memcheck:最常用的工具,用于检测程序中的内存问题。
-
Cachegrind:cache 分析器,能够提供程序中 cache 丢失和命中次数以及每个函数、每个模块产生的指令数,对于性能优化有很大帮助。
-
Callgrind:Cachegrind 的扩展功能,能够收集 Cachegrind 中所有数据信息。
-
Helgrind:用于检查多线程程序中出现的竞争问题。
-
Massif:堆栈分析器,能够提供程序运行中使用的堆栈大小。
valgrind 详细使用说明如下:
- 从 github 下载代码,地址 (https://github.com/petrpavlv/valgrind-riscv64);注: 官网的代码暂不支持 RISCV,上述 github 中支持 RISCV 版本,但兼容性有待完善。
- 使用 Luban SDK
中的工具链编译源码:
./configure --host=riscv64-unknown-linux-gnu --prefix=/xxxx/valgrind-riscv64-riscv64-linux/install make make install
- 把安装目录下的文件拷贝到 SD Card 中。注: 因为文件较大,勿直接将安装目录下的文件推到板子上。
- 在板子上设置 valgrind
依赖库所在路径:
export VALGRIND_LIB=/sdcard/install/libexec/valgrind
- 在板子上运行:
/sdcard/install/bin/valgrind /usr/local/bin/player_demo -i /sdcard/19031715_01.mp4
注意:
由于 github 中支持的 RISCV
版本兼容性不足,部分指令不支持,运行时可能会出现如下报错:
==300== Memcheck, a memory error detector ==300== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al. ==300== Using Valgrind-3.21.0.GIT and LibVEX; rerun with -h for copyright info ==300== Command: /usr/local/bin/pic_test -i /sdcard/test.jpg ==300== RISCV64 front end: standard disInstr(riscv64): unhandled instruction 0x66F5DE0B disInstr(riscv64): 0110'0110 1111'0101 1101'1110 0000'1011 ==300== valgrind: Unrecognised instruction at address 0x40016a8. ==300== at 0x40016A8: _dl_start (in /lib/ld-2.29.so) ==300== by 0x9: ??? ==300== Your program just tried to execute an instruction that Valgrind ==300== did not recognise. There are two possible reasons for this. ==300== 1. Your program has a bug and erroneously jumped to a non-code ==300== location. If you are running Memcheck and you just saw a ==300== warning about a bad jump, it's probably your program's fault. ==300== 2. The instruction is legitimate but Valgrind doesn't handle it, ==300== i.e. it's Valgrind's fault. If you think this is the case or ==300== you are not sure, please let us know and we'll try to fix it. ==300== Either way, Valgrind will now raise a SIGILL signal which will ==300== probably kill your program.