Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。
Valgrind的体系结构如下图所示:
Valgrind包括如下一些工具:
要发现Linux下的内存问题,首先一定要知道在Linux下,内存是如何被分配的?下图展示了一个典型的Linux C程序内存空间布局:
一个典型的Linux C程序内存空间由如下几部分组成:
Memcheck检测内存问题的原理如下图所示:
Memcheck 能够检测出内存问题,关键在于其建立了两个全局表。
对于进程的整个地址空间中的每一个字节(byte),都有与之对应的 8 个 bits;对于 CPU 的每个寄存器,也有一个与之对应的 bit 向量。这些 bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。
对于进程整个地址空间中的每一个字节(byte),还有与之对应的 1 个 bit,负责记录该地址是否能够被读写。
检测原理:
用法: valgrind [options] prog-and-args [options]:
选项,适用于所有Valgrind工具
LOG信息输出
适用于Memcheck工具的相关选项:
例子一:
下面是一段有问题的C程序代码test.c
#include <stdlib.h>
void f(void)
{
int* x = malloc(10 * sizeof(int));
x[10] = 0; //问题1: 数组下标越界
} //问题2: 内存没有释放
int main(void)
{
f();
return 0;
}
1、 编译程序test.c
gcc -Wall test.c -g -o test
2、 使用Valgrind检查程序BUG
valgrind --tool=memcheck --leak-check=full ./test
3、 分析输出的调试信息
==3908== Memcheck, a memory error detector.
==3908== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==3908== Using LibVEX rev 1732, a library for dynamic binary translation.
==3908== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==3908== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==3908== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==3908== For more details, rerun with: -v
==3908==
--3908-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--3908-- DWARF2 CFI reader: unhandled CFI instruction 0:50
/*数组越界错误*/
==3908== Invalid write of size 4
==3908== at 0x8048384: f (test.c:6)
==3908== by 0x80483AC: main (test.c:11)
==3908== Address 0x400C050 is 0 bytes after a block of size 40 alloc'd
==3908== at 0x40046F2: malloc (vg_replace_malloc.c:149)
==3908== by 0x8048377: f (test.c:5)
==3908== by 0x80483AC: main (test.c:11)
==3908==
==3908== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 1)
==3908== malloc/free: in use at exit: 40 bytes in 1 blocks.
==3908== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.
==3908== For counts of detected errors, rerun with: -v
==3908== searching for pointers to 1 not-freed blocks.
==3908== checked 59,124 bytes.
==3908==
==3908==
/*有内存空间没有释放*/
==3908== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3908== at 0x40046F2: malloc (vg_replace_malloc.c:149)
==3908== by 0x8048377: f (test.c:5)
==3908== by 0x80483AC: main (test.c:11)
==3908==
==3908== LEAK SUMMARY:
==3908== definitely lost: 40 bytes in 1 blocks.
==3908== possibly lost: 0 bytes in 0 blocks.
==3908== still reachable: 0 bytes in 0 blocks.
==3908== suppressed: 0 bytes in 0 blocks.
例子二:
没有内存泄漏
编译C++ -“Hello kiccleaf!”
#include <iostream.h>
int main()
{
cout << "Hello kiccleaf!/n" << endl;
return 0;
}
用g++编译C++程序
g++ Hello.cpp -o hello
检测及结果:
[root@xuanAS4 LNMP]# valgrind --tool=memcheck --leak-check=full ./hello
==8926== Memcheck, a memory error detector.
==8926== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==8926== Using LibVEX rev 1884, a library for dynamic binary translation.
==8926== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==8926== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==8926== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==8926== For more details, rerun with: -v
==8926==
Hello kiccleaf!
==8926==
==8926== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==8926== malloc/free: in use at exit: 0 bytes in 0 blocks.
==8926== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==8926== For counts of detected errors, rerun with: -v
==8926== All heap blocks were freed -- no leaks are possible
在检测之前,需要一些准备工作,需要对python源码一些进行设置,否则在检测过程中会报错。
我这里的环境是:arm开发板、python2.7
因为是交叉编译,所以需要下载valgrind源码进行交叉编译,并且对python2.7源码修改后,也需要进行交叉编译才能放在到arm板内进行检测。如果直接在机器上运行,不需要交叉编译的,请忽略这一步。
Python源码可以到python官网下载或者从我的csdn下载:
https://download.csdn.net/download/sishuihuahua/10899217
下载到本地后在linux下使用以下命令进行编译:
1、tar -xvf Python-2.7.3.tar.xz
2、./configure
3、make python Parser/pgen
4、mv python hostpython
5、mv Parser/pgen Parser/hostpgen
6、make distclean
Objects/obmalloc.c ----+704:
#define Py_USING_MEMORY_DEBUGGER
Misc/valgrind-python.supp ----+127:
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Addr4
fun:PyObject_Free
}
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Value4
fun:PyObject_Free
}
{
ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
Memcheck:Cond
fun:PyObject_Free
}
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Addr4
fun:PyObject_Realloc
}
{
ADDRESS_IN_RANGE/Invalid read of size 4
Memcheck:Value4
fun:PyObject_Realloc
}
{
ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
Memcheck:Cond
fun:PyObject_Realloc
}
补丁下载地址:
https://download.csdn.net/download/sishuihuahua/10899271
patch -p1 < ../Python-2.7.3-xcompile.patch
下载valgrind源码:
https://download.csdn.net/download/sishuihuahua/10899241
配置交叉编译:
echo ac_cv_file__dev_ptmx=no > config.site
echo ac_cv_file__dev_ptc=no >> config.site
export CONFIG_SITE=config.site
./configure CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar RANLIB=arm-linux-gnueabihf-ranlib LD=arm-linux-gnueabihf-ld NM=arm-linux-gnueabihf-nm --host=arm-linux-gnueabihf --build=x86_64-linux --disable-ipv6 --without-pymalloc --with-valgrind --with-wide-unicode --enable-unicode=ucs4
make HOSTPYTHON=./hostpython HOSTPGEN=./Parser/hostpgen BLDSHARED="arm-linux-gnueabihf-gcc -shared" CROSS_COMPILE=arm-linux-gnueabihf- CROSS_COMPILE_TARGET=yes HOSTARCH=arm-linux BUILDARCH=x86_64-linux
make install HOSTPYTHON=./hostpython BLDSHARED="arm-linux-gnueabihf-gcc -shared" CROSS_COMPILE=arm-linux-gnueabihf- CROSS_COMPILE_TARGET=yes prefix=$PWD/_install
在arm板命令行上执行如下命令,更加具体的python程序添加其他的export:
export PYTHONPATH=/usr/lib/python2.7/dist-packages
valgrind python2.7 test_main.py
执行结果个上文类似,分析的方法是一致的。
参考链接:https://blog.csdn.net/destina/article/details/6198443
至此,内存泄露的全部总结到此告一段落,算是一个总结,也是一个开始,终于是从0到1的进步。
本文地址:https://blog.csdn.net/sishuihuahua/article/details/85930419
如对本文有疑问, 点击进行留言回复!!
使用jupyter notebook运行python和R的步骤
网友评论