valgrind——内存泄漏检测介绍

文章目录

  • 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):这个段用于在程序中进行动态内存申请,例如经常用到的malloc,new系列函数就是从这个段中申请内存。
  • 栈(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工具

  1. Memcheck,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:
    • 使用未初始化的内存;
    • 使用已经释放了的内存;
    • 内存访问越界等。
  2. Callgrind,用来检查程序中函数调用过程中出现的问题。
  3. Cachegrind,用来检查程序中缓存使用出现的问题。
  4. Helgrind,用来检查多线程程序中出现的竞争问题。
  5. Massif,用来检查程序中堆栈使用中出现的问题。
  6. Extension,可以利用core提供的功能,自己编写特定的内存调试工具。
# centos 中安装
sudo yum install valgrind valgrind-devel valgrind-tools# 查看是否安装成功
valgrind --version

3. 常用选项

  1. –tool=[default: memcheck]:运行 toolname 指定的工具,默认 memcheck,还可以为cachegrid、drd、lackey、callgrind、helgrind、massif等;
  2. –leak-check=no | summary | full:对发现的内存泄露给出的信息级别,只有memcheck可用。
  3. –trace-childer=no | yes [default: no]:跟踪子线程;
  4. –log-file=:输出Log信息到指定的文件;
  5. –time-stamp=no | yes [default: no]:增加时间戳到 Log 信息;
  6. –xml=yes:将错误信息以xml格式输出,只有memcheck可用;
  7. –xml-file=:XML输出到指定文件;
  8. –error-limit=no | yes:如果错误太多,则停止显示新错误;
  9. –error-exitcode=:如果发现错误,则返回错误代码;
  10. –num-callers=(num):这个值默认是12,最高是50。表示显示多少层的堆栈,设置越高会使Valgrind运行越慢而且使用更多的内存,但是在嵌套调用层次比较高的程序中非常实用。
  11. –track-fds=no | yes:跟踪打开的文件描述;
  12. –show-reachable=no | yes:用于控制是否检测控制范围之外的泄漏,比如全局指针、static指针等;
  13. –trace-children=no | yes [default: no]:是否跟入子进程;
  14. -h, --help:显示帮助信息;
  15. –version:显示 valgrind 版本;
  16. -q, --quiet:安静地运行,只打印错误信息
  17. -v, --verbose:更详细的信息,增加错误数统计。

4. 示例

1. 内存泄漏

示例代码:

// memleak_demo.cpp
#include <iostream>int main() {int *p = new int;*p = 123;return 0;
}

编译程序时,需要加上-g选项。

g++ -g -o demo memleak_demo.cpp

执行结果(加参数 -v):

# --tool=memcheck:使用Memcheck这个工具进行内存检查
# --leak-check=full:表示开启全面的内存泄漏检查,该选项会告诉Valgrind输出详情并报告所有未释放的情况。
# -v:获得更详细的信息。
# 
-->$ valgrind --tool=memcheck --leak-check=full -v ./demo 
==11763== Memcheck, a memory error detector
==11763== Copyright (C) 2002-2012, and GNU GPL'd, 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--    --tool=memcheck
--11763--    --leak-check=full
--11763--    -v
--11763-- Contents of /proc/version:
--11763--   Linux version 2.6.32-642.6.2.el6.x86_64 (mockbuild@worker1.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 doesn't 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== don't want to do, unless you know exactly what you're doing,
==11763== or are doing some strange experiment):
==11763==   /usr/lib64/valgrind/../../bin/vgdb --pid=11763 ...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 --pid=11763
==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 doesn't 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 doesn't 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 --tool=memcheck --leak-check=full ./demo 
==12383== Memcheck, a memory error detector
==12383== Copyright (C) 2002-2012, and GNU GPL'd, 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 <iostream>int main() {int arr[10] = {0};std::cout << arr[10] << std::endl;return 0;
}

执行结果:

-->$ g++ -g -o demo memleak_demo.cpp
-->$ valgrind --tool=memcheck --leak-check=full  ./demo 
==15091== Memcheck, a memory error detector
==15091== Copyright (C) 2002-2012, and GNU GPL'd, 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_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EB0E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EC443D: std::ostream& std::ostream::_M_insert<long>(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_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EB0E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EC443D: std::ostream& std::ostream::_M_insert<long>(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_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EB0E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EC443D: std::ostream& std::ostream::_M_insert<long>(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_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EB0E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==15091==    by 0x4EC443D: std::ostream& std::ostream::_M_insert<long>(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-origins=yes 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 <iostream>int main() {std::vector<int> v(10, 0);std::cout << v[10] << std::endl;return 0;
}

执行结果:

-->$ g++ -g -o demo memleak_demo.cpp
-->$ valgrind --tool=memcheck --leak-check=full  ./demo 
==19508== Memcheck, a memory error detector
==19508== Copyright (C) 2002-2012, and GNU GPL'd, 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 alloc'd
==19508==    at 0x4C285FC: operator new(unsigned long) (vg_replace_malloc.c:298)
==19508==    by 0x400FAB: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
==19508==    by 0x400EA8: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (in /data/neilnie/mypro/cp/linuxperf/valgrind/demo)
==19508==    by 0x400D86: void std::vector<int, std::allocator<int> >::_M_initialize_dispatch<int>(int, int, std::__true_type) (stl_vector.h:1163)
==19508==    by 0x400BF0: std::vector<int, std::allocator<int> >::vector<int>(int, int, std::allocator<int> 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.h>int main() {char x[10];int i;for (i=0;i<10;i++) {x[i] = i+1;}strncpy(x+3,x,4);for (i=0;i<10;i++) {printf("x(%d) = %d)\n", i, x[i]);}return 0;
}

执行结果:

-->$ g++ -g -o demo memleak_demo.cpp
-->$ valgrind --tool=memcheck --leak-check=full  ./demo 
==9862== Memcheck, a memory error detector
==9862== Copyright (C) 2002-2012, and GNU GPL'd, 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 strncpy,13号代码strncpy发生内存覆盖。

4. 使用未初始化的值

示例:

// memleak_demo.cpp
#include <iostream>int main() {int n;if (n == 0) {std::cout << "n is zero" << std::endl;}return 0;
}

执行结果:

-->$ g++ -g -o demo memleak_demo.cpp
-->$ valgrind --tool=memcheck --leak-check=full  ./demo 
==16762== Memcheck, a memory error detector
==16762== Copyright (C) 2002-2012, and GNU GPL'd, 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-origins=yes 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 <iostream>int main() {int *p = NULL;p = (int*)malloc(sizeof(int));if (p == NULL) {std::cout<<"malloc failed"<<std::endl;}std::cout<<"address [0x%p]"<<std::endl;delete p;return 0;
}

执行结果:

-->$ g++ -g -o demo memleak_demo.cpp
-->$ valgrind --tool=memcheck --leak-check=full  ./demo 
==476== Memcheck, a memory error detector
==476== Copyright (C) 2002-2012, and GNU GPL'd, 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 alloc'd
==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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/16843.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动端个人中心UI设计

效果图 源码如下 页面设计 <template><div class"container"><!-- 顶部用户信息 start--><div class"header"><div class"user-info"><van-image class"user-img" round width"70" :sr…

HCIP--云计算题库 V5.0版本

在国家政策的支持下&#xff0c;我国云计算应用市场发展明显加快&#xff0c;越来越多的企业开始介入云产业&#xff0c;出现了大量的应用解决方案&#xff0c;云应用的成功案例逐渐丰富&#xff0c;用户了解和认可程度不断提高&#xff0c;云计算产业发展迎来了“黄金机遇期”…

【ArcGIS Pro二次开发】(55):给多个要素或表批量添加字段

在工作中可能会遇到这样的场景&#xff1a;有多个GDB要素、表格&#xff0c;或者是SHP文件&#xff0c;需要给这个要素或表添加相同的多个字段。 在这种情况下&#xff0c;手动添加就变得很繁琐&#xff0c;于是就做了这个工具。 需求具体如下图&#xff1a; 左图是待处理数据…

C数据结构——无向图(邻接矩阵方式) 创建与基本使用

源码注释 // // Created by Lenovo on 2022-05-13-上午 9:06. // 作者&#xff1a;小象 // 版本&#xff1a;1.0 //#include <stdio.h> #include <malloc.h>#define MAXSIZE 1000 // BFS队列可能达到的最大长度 #define MAX_AMVNUMS 100 // 最大顶点数typedef enu…

电脑剪辑视频的软件有哪些?试试这几种视频剪辑工具

视频剪辑可以帮助人们在不同情境下更好地理解和消化视频内容。通过剪辑&#xff0c;可以去除不必要的素材并突出重点&#xff0c;使观看者能够更快地获取信息&#xff0c;并且更容易保持注意力的集中。此外&#xff0c;剪辑可以提高视频质量&#xff0c;例如通过添加音乐、图形…

CVPR2023新作:源数据集对迁移学习性能的影响以及相应的解决方案

Title: A Data-Based Perspective on Transfer Learning (迁移学习的基于数据的观点) Affiliation: MIT (麻省理工学院) Authors: Saachi Jain, Hadi Salman, Alaa Khaddaj, Eric Wong, Sung Min Park, Aleksander Mądry Keywords: transfer learning, source dataset, dow…

Git分布式版本控制工具和GitHub(二)--Git指令入门

一.指令入门前的准备 1.Git全局设置 2.获取Git仓库 例如&#xff1a;将我GitHub上的first_resp仓库克隆到本地。 点击进入first_rep&#xff0c;后面本地仓库操作的学习就是在这个界面右键打开Git Bash 3.工作区&#xff0c;暂存区&#xff0c;版本库概念 注&#xff1a;如果空…

Reinforcement-Learning

文章目录 Reinforcement-Learning1. RL方法分类汇总&#xff1a;2. Q-Learning3. SARSA算法4. SARSA&#xff08;λ&#xff09; Reinforcement-Learning 1. RL方法分类汇总&#xff1a; &#xff08;1&#xff09;不理解环境&#xff08;Model-Free RL&#xff09;&#xff…

【【51单片机的红外遥控】】

红外遥控&#xff0c;完全把控 红外遥控 利用红外光进行通信的设备&#xff0c;由红外LED将调制后的信号发出&#xff0c;再由专门的红外接收头进行解调输出 通信方式&#xff1a;单工 异步 红外LED波长&#xff1a;940nm 通信协议标准&#xff1a;NEC标准 用那种一体化红红外…

【MySQL】模具数据转移处理

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

SQL注入之布尔盲注

SQL注入之布尔盲注 一、布尔盲注介绍二、布尔盲注的特性三、布尔盲注流程3.1、确定注入点3.2、判断数据库的版本3.3、判断数据库的长度3.4、猜解当前数据库名称&#xff08;本步骤需要重复&#xff09;3.5、猜解数据表的数量3.6、猜解第一个数据表名称的长度3.7、猜解第一个数据…

初识Java - 概念与准备

本笔记参考自&#xff1a; 《On Java 中文版》 目录 写在第一行 Java的迭代与发展 Java的迭代 Java的参考文档 对象的概念 抽象 接口 访问权限 复用实现 继承 基类和子类 A是B和A像B 多态 单根层次结构 集合 参数化类型 对象的创建和生命周期 写在第一行 作为一…

从SQL注入绕过最新安全狗WAF中学习fuzz

前言 SQL注入并不是很精通&#xff0c;通过实战绕过WAF来进行加强SQL注入能力&#xff0c;希望对正在学习的师傅能有一丝帮助。 安装 安装前言 我是本地搭建的环境进行测试的 环境是windows11phpstudy2018sqli-labs phpstudy的安装我不再复述&#xff0c;这里简单说一下安全…

PDF文件忘记密码,怎么办?

PDF文件设置密码分为打开密码和限制密码&#xff0c;忘记了密码分别如何解密PDF密码&#xff1f; 如果是限制编辑密码忘记了&#xff0c;我们可以试着将PDF文件转换成其他格式来避开限制编辑&#xff0c;然后重新将文件转换回PDF格式就可以了。 如果因为转换之后导致文件格式…

【100天精通python】Day20:文件及目录操作_os模块和os.psth模块, 文件路径拼接,目录操作

目录 专栏导读 1 文件的目录操作 os模块的一些操作目录函数​编辑 os.path 模块的操作目录函数 2 相对路径和绝对路径 3 路径拼接 4 判断目录是否存在 5 创建目录、删除目录、遍历目录 专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/qq_35831906/category_12…

Day03-作业(AxiosElementUI)

作业1&#xff1a; 根据需求完成如下页面数据列表展示 需求&#xff1a;Vue挂载完成后,通过axios发送异步请求到服务端,获取学生列表数据,并通过Vue展示在页面上 获取数据url&#xff1a;http://yapi.smart-xwork.cn/mock/169327/student 素材&#xff1a; <!DOCTYPE html…

springboot2实现图片文件上传与mysql存储路径并回显

环境介绍 技术栈 springbootmybatismysql 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 1.8 Spring Boot 2.7.13 mybatis 2.3.1 springboot是基于spring 4.0&#xff0c;springboot2是基于spring5.0,springboot2由pivotal公司在2018发布,这个框架主要用来…

螺旋矩阵 II——力扣59

文章目录 题目描述法一 模拟 题目描述 法一 模拟 初始化一个二维向量&#xff0c;名为matrix&#xff0c;它有n行和n列。向量的每个元素都是一个整数&#xff0c;初始化为0。初始化二维向量的语法如下&#xff1a;vector<vector<int>> matrix(n, vector<int>…

WPS本地镜像化在线文档操作以及样例

一个客户项目有引进在线文档操作需求&#xff0c;让我这边做一个demo调研下&#xff0c;给我的对接文档里有相关方法的说明&#xff0c;照着对接即可。但在真正对接过程中还是踩过不少坑&#xff0c;这儿对之前的对接工作做个记录。 按照习惯先来一个效果&#xff1a; Demo下载…

【phaser微信抖音小游戏开发002】hello world!

执行效果&#xff1a; 将以下代码文本内容&#xff0c;放入到game.js中即可。目录结构如下图 import ./js/libs/weapp-adapter import ./js/libs/symbolGameGlobal.window.scrollTo () > { };//防止真机出错 import Phaser from ./js/phaser//引入Phaservar {windowWidth, …