做移动网站设计,网站运营工资,公司部门组织架构图,有免费网站推荐吗文章目录 1. 概述1. 体系结构2. Linux 程序内存空间布局3. 内存检查原理 2. valgrind工具3. 常用选项4. 示例1. 内存泄漏2. 数组越界3. 内存覆盖4. 使用未初始化的值5. 内存申请与释放函数不匹配 5. 总结 1. 概述
1. 体系结构
Valgrind 是一套 Linux 下#xff0c;开放源代码… 文章目录 1. 概述1. 体系结构2. Linux 程序内存空间布局3. 内存检查原理 2. valgrind工具3. 常用选项4. 示例1. 内存泄漏2. 数组越界3. 内存覆盖4. 使用未初始化的值5. 内存申请与释放函数不匹配 5. 总结 1. 概述
1. 体系结构
Valgrind 是一套 Linux 下开放源代码GPL V2的仿真调试工具的集合。 Valgrind模拟了一个 CPU 环境并提供服务给其他工具而其他工具则类似于插件 (plug-in)利用内核提供的服务完成各种特定的内存调试任务。 体系结构如下图所示
2. Linux 程序内存空间布局
要发现Linux下的内存问题首先要知道在Linux下内存是如何被分配的Linux C程序内存空间布局如下
代码段.text存放CPU要执行的指令。代码段是可共享的相同的代码在内存中只会有一个拷贝同时这个段是只读的。初始化数据段.data存放的是程序中需要明确赋初始值的变量例如位于所有函数之外的全局变量。未初始化数据段.bss位于这一段中的数据内核在执行该程序前将其初始化为0或者null。例如出现在任何函数之外的全局变量int sum;堆Heap这个段用于在程序中进行动态内存申请例如经常用到的mallocnew系列函数就是从这个段中申请内存。栈Stack函数中的局部变量以及在函数调用过程中产生的临时变量都保存在此段中。
3. 内存检查原理
Memcheck检测内存问题的原理如下图所示
Memcheck 能够检测出内存问题关键在于其建立了两个全局表
Valid-Value 表 对于进程的整个地址空间中的每一个字节(byte)都有与之对应的 8 个 bits对于 CPU 的每个寄存器也有一个与之对应的 bit 向量。这些 bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。Valid-Address 表 对于进程整个地址空间中的每一个字节(byte)还有与之对应的 1 个 bit负责记录该地址是否能够被读写。
检测原理
当要读写内存中某个字节时首先检查这个字节对应的 A bit。如果该A bit显示该位置是无效位置memcheck 则报告读写错误。内核core类似于一个虚拟的 CPU 环境这样当内存中的某个字节被加载到真实的 CPU 中时该字节对应的 V bit 也被加载到虚拟的 CPU 环境中。一旦寄存器中的值被用来产生内存地址或者该值能够影响程序输出则 memcheck 会检查对应的V bits如果该值尚未初始化则会报告使用未初始化内存错误。
2. valgrind工具
Memcheck一个重量级的内存检查器能够发现开发中绝大多数内存错误使用情况比如 使用未初始化的内存使用已经释放了的内存内存访问越界等。 Callgrind用来检查程序中函数调用过程中出现的问题。Cachegrind用来检查程序中缓存使用出现的问题。Helgrind用来检查多线程程序中出现的竞争问题。Massif用来检查程序中堆栈使用中出现的问题。Extension可以利用core提供的功能自己编写特定的内存调试工具。
# centos 中安装
sudo yum install valgrind valgrind-devel valgrind-tools# 查看是否安装成功
valgrind --version3. 常用选项
–tool[default: memcheck]运行 toolname 指定的工具默认 memcheck还可以为cachegrid、drd、lackey、callgrind、helgrind、massif等–leak-checkno | summary | full对发现的内存泄露给出的信息级别只有memcheck可用。–trace-childerno | yes [default: no]跟踪子线程–log-file输出Log信息到指定的文件–time-stampno | yes [default: no]增加时间戳到 Log 信息–xmlyes将错误信息以xml格式输出只有memcheck可用–xml-fileXML输出到指定文件–error-limitno | yes如果错误太多则停止显示新错误–error-exitcode如果发现错误则返回错误代码–num-callers(num)这个值默认是12最高是50。表示显示多少层的堆栈设置越高会使Valgrind运行越慢而且使用更多的内存,但是在嵌套调用层次比较高的程序中非常实用。–track-fdsno | yes跟踪打开的文件描述–show-reachableno | yes用于控制是否检测控制范围之外的泄漏比如全局指针、static指针等–trace-childrenno | yes [default: no]是否跟入子进程-h, --help显示帮助信息–version显示 valgrind 版本-q, --quiet安静地运行只打印错误信息-v, --verbose更详细的信息增加错误数统计。
4. 示例
1. 内存泄漏
示例代码
// memleak_demo.cpp
#include iostreamint main() {int *p new int;*p 123;return 0;
}编译程序时需要加上-g选项。
g -g -o demo memleak_demo.cpp执行结果(加参数 -v)
# --toolmemcheck使用Memcheck这个工具进行内存检查
# --leak-checkfull表示开启全面的内存泄漏检查该选项会告诉Valgrind输出详情并报告所有未释放的情况。
# -v获得更详细的信息。
#
--$ valgrind --toolmemcheck --leak-checkfull -v ./demo
11763 Memcheck, a memory error detector
11763 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
11763 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
11763 Command: ./demo
11763
--11763-- Valgrind options:
--11763-- --toolmemcheck
--11763-- --leak-checkfull
--11763-- -v
--11763-- Contents of /proc/version:
--11763-- Linux version 2.6.32-642.6.2.el6.x86_64 (mockbuildworker1.bsys.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) ) #1 SMP Wed Oct 26 06:52:09 UTC 2016
--11763-- Arch and hwcaps: AMD64, amd64-sse3-cx16-lzcnt-avx2-bmi
--11763-- Page sizes: currently 4096, max supported 4096
--11763-- Valgrind library directory: /usr/lib64/valgrind
--11763-- Reading syms from /data/neilnie/mypro/cp/linuxperf/valgrind/demo
--11763-- Reading syms from /lib64/ld-2.12.so
--11763-- Reading syms from /usr/lib64/valgrind/memcheck-amd64-linux
--11763-- object doesnt have a dynamic symbol table
--11763-- Scheduler: using generic scheduler lock implementation.
--11763-- Reading suppressions file: /usr/lib64/valgrind/default.supp
11763 embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-11763-by-neilnie-on-QC_GZ-172_24_19_228-neil_dev
11763 embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-11763-by-neilnie-on-QC_GZ-172_24_19_228-neil_dev
11763 embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-11763-by-neilnie-on-QC_GZ-172_24_19_228-neil_dev
11763
11763 TO CONTROL THIS PROCESS USING vgdb (which you probably
11763 dont want to do, unless you know exactly what youre doing,
11763 or are doing some strange experiment):
11763 /usr/lib64/valgrind/../../bin/vgdb --pid11763 ...command...
11763
11763 TO DEBUG THIS PROCESS USING GDB: start GDB like this
11763 /path/to/gdb ./demo
11763 and then give GDB the following command
11763 target remote | /usr/lib64/valgrind/../../bin/vgdb --pid11763
11763 --pid is optional if only one valgrind process is running
11763
--11763-- REDIR: 0x4017c30 (strlen) redirected to 0x38049551 (vgPlain_amd64_linux_REDIR_FOR_strlen)
--11763-- Reading syms from /usr/lib64/valgrind/vgpreload_core-amd64-linux.so
--11763-- Reading syms from /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so
--11763-- REDIR: 0x4017a40 (index) redirected to 0x4c28c30 (index)
--11763-- REDIR: 0x4017ac0 (strcmp) redirected to 0x4c29570 (strcmp)
--11763-- Reading syms from /usr/lib64/libstdc.so.6.0.13
--11763-- object doesnt have a symbol table
--11763-- Reading syms from /lib64/libm-2.12.so
--11763-- Reading syms from /lib64/libgcc_s-4.4.7-20120601.so.1
--11763-- object doesnt have a symbol table
--11763-- Reading syms from /lib64/libc-2.12.so
--11763-- REDIR: 0x5653d00 (strcasecmp) redirected to 0x4a2255c (_vgnU_ifunc_wrapper)
--11763-- REDIR: 0x5655fc0 (strncasecmp) redirected to 0x4a2255c (_vgnU_ifunc_wrapper)
--11763-- REDIR: 0x5651c70 (__GI_strrchr) redirected to 0x4c28ab0 (__GI_strrchr)
--11763-- REDIR: 0x5650190 (__GI_strlen) redirected to 0x4c28fb0 (__GI_strlen)
--11763-- REDIR: 0x564e710 (strcmp) redirected to 0x4a2255c (_vgnU_ifunc_wrapper)
--11763-- REDIR: 0x564e750 (__GI_strcmp) redirected to 0x4c29520 (__GI_strcmp)
--11763-- REDIR: 0x4eec0b0 (operator new(unsigned long)) redirected to 0x4c2857a (operator new(unsigned long))
--11763-- REDIR: 0x564a920 (free) redirected to 0x4c273a9 (free)
11763
11763 HEAP SUMMARY:
11763 in use at exit: 4 bytes in 1 blocks
11763 total heap usage: 1 allocs, 0 frees, 4 bytes allocated
11763
11763 Searching for pointers to 1 not-freed blocks
11763 Checked 179,320 bytes
11763
11763 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
11763 at 0x4C285FC: operator new(unsigned long) (vg_replace_malloc.c:298)
11763 by 0x400741: main (memleak_demo.cpp:5)
11763
11763 LEAK SUMMARY:
11763 definitely lost: 4 bytes in 1 blocks
11763 indirectly lost: 0 bytes in 0 blocks
11763 possibly lost: 0 bytes in 0 blocks
11763 still reachable: 0 bytes in 0 blocks
11763 suppressed: 0 bytes in 0 blocks
11763
11763 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
--11763--
--11763-- used_suppression: 4 U1004-ARM-_dl_relocate_object
--11763-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a
11763
11763 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)执行结果(不加参数 -v)
--$ valgrind --toolmemcheck --leak-checkfull ./demo
12383 Memcheck, a memory error detector
12383 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
12383 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
12383 Command: ./demo
12383
12383
12383 HEAP SUMMARY:
12383 in use at exit: 4 bytes in 1 blocks
12383 total heap usage: 1 allocs, 0 frees, 4 bytes allocated
12383
12383 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
12383 at 0x4C285FC: operator new(unsigned long) (vg_replace_malloc.c:298)
12383 by 0x400741: main (memleak_demo.cpp:5)
12383
12383 LEAK SUMMARY:
12383 definitely lost: 4 bytes in 1 blocks
12383 indirectly lost: 0 bytes in 0 blocks
12383 possibly lost: 0 bytes in 0 blocks
12383 still reachable: 0 bytes in 0 blocks
12383 suppressed: 0 bytes in 0 blocks
12383
12383 For counts of detected and suppressed errors, rerun with: -v
12383 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)definitely lost内存泄漏另外可以看到有4个字节的内存泄漏。
2. 数组越界
示例1 代码
// memleak_demo.cpp
#include iostreamint main() {int arr[10] {0};std::cout arr[10] std::endl;return 0;
}执行结果
--$ g -g -o demo memleak_demo.cpp
--$ valgrind --toolmemcheck --leak-checkfull ./demo
15091 Memcheck, a memory error detector
15091 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
15091 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
15091 Command: ./demo
15091
15091 Conditional jump or move depends on uninitialised value(s)
15091 at 0x4EB0B96: std::ostreambuf_iteratorchar, std::char_traitschar std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::_M_insert_intlong(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0E25: std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::do_put(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EC443D: std::ostream std::ostream::_M_insertlong(long) (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x40087E: main (memleak_demo.cpp:6)
15091
15091 Use of uninitialised value of size 8
15091 at 0x4EAC6B3: ??? (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0BC2: std::ostreambuf_iteratorchar, std::char_traitschar std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::_M_insert_intlong(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0E25: std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::do_put(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EC443D: std::ostream std::ostream::_M_insertlong(long) (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x40087E: main (memleak_demo.cpp:6)
15091
15091 Conditional jump or move depends on uninitialised value(s)
15091 at 0x4EAC6BE: ??? (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0BC2: std::ostreambuf_iteratorchar, std::char_traitschar std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::_M_insert_intlong(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0E25: std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::do_put(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EC443D: std::ostream std::ostream::_M_insertlong(long) (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x40087E: main (memleak_demo.cpp:6)
15091
15091 Conditional jump or move depends on uninitialised value(s)
15091 at 0x4EB0BF8: std::ostreambuf_iteratorchar, std::char_traitschar std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::_M_insert_intlong(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EB0E25: std::num_putchar, std::ostreambuf_iteratorchar, std::char_traitschar ::do_put(std::ostreambuf_iteratorchar, std::char_traitschar , std::ios_base, char, long) const (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x4EC443D: std::ostream std::ostream::_M_insertlong(long) (in /usr/lib64/libstdc.so.6.0.13)
15091 by 0x40087E: main (memleak_demo.cpp:6)
15091
0
15091
15091 HEAP SUMMARY:
15091 in use at exit: 0 bytes in 0 blocks
15091 total heap usage: 0 allocs, 0 frees, 0 bytes allocated
15091
15091 All heap blocks were freed -- no leaks are possible
15091
15091 For counts of detected and suppressed errors, rerun with: -v
15091 Use --track-originsyes to see where uninitialised values come from
15091 ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 6 from 6)IConditional jump or move depends on uninitialised value(s) 访问了未初始化的内存访问数组越界。
示例2 代码
// memleak_demo.cpp
#include vector
#include iostreamint main() {std::vectorint v(10, 0);std::cout v[10] std::endl;return 0;
}执行结果
--$ g -g -o demo memleak_demo.cpp
--$ valgrind --toolmemcheck --leak-checkfull ./demo
19508 Memcheck, a memory error detector
19508 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
19508 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
19508 Command: ./demo
19508
19508 Invalid read of size 4
19508 at 0x400ABF: main (memleak_demo.cpp:7)
19508 Address 0x5963068 is 0 bytes after a block of size 40 allocd
19508 at 0x4C285FC: operator new(unsigned long) (vg_replace_malloc.c:298)
19508 by 0x400FAB: __gnu_cxx::new_allocatorint::allocate(unsigned long, void const*) (new_allocator.h:104)
19508 by 0x400EA8: std::_Vector_baseint, std::allocatorint ::_M_allocate(unsigned long) (in /data/neilnie/mypro/cp/linuxperf/valgrind/demo)
19508 by 0x400D86: void std::vectorint, std::allocatorint ::_M_initialize_dispatchint(int, int, std::__true_type) (stl_vector.h:1163)
19508 by 0x400BF0: std::vectorint, std::allocatorint ::vectorint(int, int, std::allocatorint const) (stl_vector.h:404)
19508 by 0x400AA1: main (memleak_demo.cpp:6)
19508
0
19508
19508 HEAP SUMMARY:
19508 in use at exit: 0 bytes in 0 blocks
19508 total heap usage: 1 allocs, 1 frees, 40 bytes allocated
19508
19508 All heap blocks were freed -- no leaks are possible
19508
19508 For counts of detected and suppressed errors, rerun with: -v
19508 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)Invalid read of size 4 表示越界读取 4 个字节这个操作出现在 memleak_demo.cpp 文件的第 7 行。另外可以看到vector 分配了一块 40 字节的内存程序越界访问这块内存之后的 4 个字节。
3. 内存覆盖
示例
// memleak_demo.cpp
#include string.h
#include stdio.h
#include stdlib.hint main() {char x[10];int i;for (i0;i10;i) {x[i] i1;}strncpy(x3,x,4);for (i0;i10;i) {printf(x(%d) %d)\n, i, x[i]);}return 0;
}执行结果
--$ g -g -o demo memleak_demo.cpp
--$ valgrind --toolmemcheck --leak-checkfull ./demo
9862 Memcheck, a memory error detector
9862 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
9862 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
9862 Command: ./demo
9862
9862 Source and destination overlap in strncpy(0x7ff0003a7, 0x7ff0003a4, 4)
9862 at 0x4C2937F: __GI_strncpy (mc_replace_strmem.c:477)
9862 by 0x400687: main (memleak_demo.cpp:13)
9862
x(0) 1)
x(1) 2)
x(2) 3)
x(3) 1)
x(4) 2)
x(5) 3)
x(6) 1)
x(7) 8)
x(8) 9)
x(9) 10)
9862
9862 HEAP SUMMARY:
9862 in use at exit: 0 bytes in 0 blocks
9862 total heap usage: 0 allocs, 0 frees, 0 bytes allocated
9862
9862 All heap blocks were freed -- no leaks are possible
9862
9862 For counts of detected and suppressed errors, rerun with: -v
9862 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)Source and destination overlap in strncpy13号代码strncpy发生内存覆盖。
4. 使用未初始化的值
示例
// memleak_demo.cpp
#include iostreamint main() {int n;if (n 0) {std::cout n is zero std::endl;}return 0;
}执行结果
--$ g -g -o demo memleak_demo.cpp
--$ valgrind --toolmemcheck --leak-checkfull ./demo
16762 Memcheck, a memory error detector
16762 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
16762 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
16762 Command: ./demo
16762
16762 Conditional jump or move depends on uninitialised value(s)
16762 at 0x40087C: main (memleak_demo.cpp:6)
16762
n is zero
16762
16762 HEAP SUMMARY:
16762 in use at exit: 0 bytes in 0 blocks
16762 total heap usage: 0 allocs, 0 frees, 0 bytes allocated
16762
16762 All heap blocks were freed -- no leaks are possible
16762
16762 For counts of detected and suppressed errors, rerun with: -v
16762 Use --track-originsyes to see where uninitialised values come from
16762 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)uninitialised value(s) memleak_demo.cpp第6行使用了未初始化内存。
5. 内存申请与释放函数不匹配
示例代码
// memleak_demo.cpp
#include stdlib.h
#include iostreamint main() {int *p NULL;p (int*)malloc(sizeof(int));if (p NULL) {std::coutmalloc failedstd::endl;}std::coutaddress [0x%p]std::endl;delete p;return 0;
}执行结果
--$ g -g -o demo memleak_demo.cpp
--$ valgrind --toolmemcheck --leak-checkfull ./demo
476 Memcheck, a memory error detector
476 Copyright (C) 2002-2012, and GNU GPLd, by Julian Seward et al.
476 Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
476 Command: ./demo
476
address [0x%p]
476 Mismatched free() / delete / delete []
476 at 0x4C27016: operator delete(void*) (vg_replace_malloc.c:480)
476 by 0x400978: main (memleak_demo.cpp:12)
476 Address 0x5963040 is 0 bytes inside a block of size 4 allocd
476 at 0x4C27A2E: malloc (vg_replace_malloc.c:270)
476 by 0x400929: main (memleak_demo.cpp:7)
476
476
476 HEAP SUMMARY:
476 in use at exit: 0 bytes in 0 blocks
476 total heap usage: 1 allocs, 1 frees, 4 bytes allocated
476
476 All heap blocks were freed -- no leaks are possible
476
476 For counts of detected and suppressed errors, rerun with: -v
476 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)在 C 中内存分配和释放规则
如果使用 malloc、calloc、realloc、valloc 或 memalign 分配则必须使用 free 释放。如果使用 new 分配则必须使用 delete 释放。如果使用 new[] 分配则必须使用 delete[] 释放。
5. 总结
valgrind是一款非常强大的内存泄漏检测工具在我们的项目和学习中有很大的作用尤其是从事C/C开发人员。 相关文献 https://valgrind.org/ https://man7.org/linux/man-pages/man1/valgrind.1.html