删除所有动态内存后出现 valgrind 泄漏错误
valgrind leak error after deletion of all dynamic memory
我尝试学习 CPP 指针以及释放我使用过的所有内存 valgrind
。但不幸的是,我遇到了泄漏错误,我不知道我在哪里犯了错误。也没有太多关于从 valgrind 中发现错误的想法作为一种人类可读的方式。非常感谢任何查找泄漏的指导。
编译器: g++ (Ubuntu 7.5.0-3ubuntu1~16.04) 7.5.0
关于片段的相关信息
smart pointer
不是有意使用
- 这是一个最小的示例代码。所以,有些部分似乎是不必要的。
file.cpp
#include <iostream>
void algo_fun(unsigned int* ip_ptr_array_,
unsigned int ip_size_,
unsigned int** op_ptr_array_,
unsigned int* op_size_)
{
*(op_size_) = ip_size_ + 2;
// following approach is good as it allocate dynamic memory
unsigned int* local = new unsigned int[*(op_size_)];
for (unsigned int i = 0; i< *(op_size_); i++)
{
local[i]=i+1*3;
}
*op_ptr_array_ = &local[0];
local[3] = 87;
}
int main()
{
// input array's contetnt
unsigned int ip_size = 10;
unsigned int* ip_ptr_array = new unsigned int[ip_size];
// output data
unsigned int op_size;
unsigned int* op_ptr_array;
// filling input array
for(unsigned int i = 0; i < ip_size; i++)
{
ip_ptr_array[i] = i+2*2;
}
// function calling to get output data
algo_fun(ip_ptr_array,
ip_size,
&op_ptr_array,
&op_size);
delete [] ip_ptr_array;
delete [] op_ptr_array;
return 0;
}
将找到工作版本 here。
用于测试的命令: valgrind --leak-check=full --show-leak-kinds=all -v ./file
Leak Summary from valgrind
==23138== LEAK SUMMARY:
==23138== definitely lost: 0 bytes in 0 blocks
==23138== indirectly lost: 0 bytes in 0 blocks
==23138== possibly lost: 0 bytes in 0 blocks
==23138== still reachable: 72,704 bytes in 1 blocks
==23138== suppressed: 0 bytes in 0 blocks
==23138==
==23138== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==23138== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
tl;dr 请检查您使用的是不是最新的 Valgrind。
结合使用 Valgrind 和 gdb,您应该能够看到发生了什么。
我得到以下信息(FreeBSD 12.2、g++ 10.3.0、从 git HEAD 构建的 Valgrind,[OS 和编译器版本不相关])。我正在使用 --trace-malloc=yes
选项查看所有 mallloc/free 调用。不要在大型应用程序上这样做。
$ valgrind --leak-check=full --trace-malloc=yes ./test
--61886-- malloc(72704) = 0x5800040
--61886-- calloc(1984,1) = 0x5811C80
--61886-- calloc(104,1) = 0x5812480
--61886-- calloc(224,1) = 0x5812530
--61886-- calloc(80,1) = 0x5812650
--61886-- calloc(520,1) = 0x58126E0
--61886-- calloc(88,1) = 0x5812930
--61886-- _Znam(40) = 0x58129D0
--61886-- _Znam(48) = 0x5812A40
--61886-- _ZdaPv(0x58129D0)
--61886-- _ZdaPv(0x5812A40)
--61886-- free(0x5800040)
==61886==
==61886== HEAP SUMMARY:
==61886== in use at exit: 3,000 bytes in 6 blocks
==61886== total heap usage: 9 allocs, 3 frees, 75,792 bytes allocated
_Znam 是 array new 的错位版本,_ZdaPv 是代码中 array delete 的错位版本。对 malloc/calloc/free 的其他调用来自 libc/libstc++。您可能会在 Linux 或 libc++ 上看到不同的痕迹。
您可以使用 --show-reachable=yes
获取有关可用内存的信息。
如果我现在运行在gdb下
$ gdb ./test
(gdb) b malloc
(gdb) b malloc
(gdb) r
Breakpoint 1, malloc (nbytes=96) at /usr/src/libexec/rtld-elf/rtld.c:5877
这是对 link 加载程序 ld.so 中的 malloc 的调用。然后我又执行了几个'r'直到
Breakpoint 1, __je_malloc_initialized () at jemalloc_jemalloc.c:208
此处 link 加载程序已加载 libstdc++.so 并且全局 malloc 已被 jemalloc 替换。
获取调用堆栈
(gdb) bt
#0 __je_malloc_initialized () at jemalloc_jemalloc.c:208
#1 imalloc (sopts=<optimized out>, dopts=<optimized out>) at jemalloc_jemalloc.c:1990
#2 __malloc (size=72704) at jemalloc_jemalloc.c:2042
#3 0x00000008006eb6f4 in ?? () from /usr/local/lib/gcc10/libstdc++.so.6
#4 0x000000080060e2fd in objlist_call_init (list=<optimized out>, lockstate=<optimized out>) at /usr/src/libexec/rtld-elf/rtld.c:2820
#5 0x000000080060d03d in _rtld (sp=0x7fffffffe408, exit_proc=0x7fffffffe3d0, objp=0x7fffffffe3d8) at /usr/src/libexec/rtld-elf/rtld.c:811
#6 0x000000080060a8c9 in rtld_start () at /usr/src/libexec/rtld-elf/amd64/rtld_start.S:39
#7 0x0000000000000000 in ?? ()
(gdb)
注意第 #2
行的相同分配大小。
我不打算深入研究这个内存的用途,它是 C++ 运行time 的一部分。
libstdc++(和 libc)故意不释放此内存(大概这很难或不值得)。为了过滤掉这些分配,Valgrind 使用一个特殊函数要求 libstc++/libc 释放这些内存。
本例中的选项是
--run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux
(严格来说,不仅仅是Linux)。
查看 Valgrind 发行说明
Release 3.12.0 (20 October 2016)
...
* New option --run-cxx-freeres=<yes|no> can be used to change whether
__gnu_cxx::__freeres() cleanup function is called or not. Default is
'yes'.
所以我假设您使用的是 3.11 或更早版本。
最后,如果我使用 clang++/libc++,则没有 运行时间分配(也没有 freeres 函数)。
我尝试学习 CPP 指针以及释放我使用过的所有内存 valgrind
。但不幸的是,我遇到了泄漏错误,我不知道我在哪里犯了错误。也没有太多关于从 valgrind 中发现错误的想法作为一种人类可读的方式。非常感谢任何查找泄漏的指导。
编译器: g++ (Ubuntu 7.5.0-3ubuntu1~16.04) 7.5.0
关于片段的相关信息
smart pointer
不是有意使用- 这是一个最小的示例代码。所以,有些部分似乎是不必要的。
file.cpp
#include <iostream>
void algo_fun(unsigned int* ip_ptr_array_,
unsigned int ip_size_,
unsigned int** op_ptr_array_,
unsigned int* op_size_)
{
*(op_size_) = ip_size_ + 2;
// following approach is good as it allocate dynamic memory
unsigned int* local = new unsigned int[*(op_size_)];
for (unsigned int i = 0; i< *(op_size_); i++)
{
local[i]=i+1*3;
}
*op_ptr_array_ = &local[0];
local[3] = 87;
}
int main()
{
// input array's contetnt
unsigned int ip_size = 10;
unsigned int* ip_ptr_array = new unsigned int[ip_size];
// output data
unsigned int op_size;
unsigned int* op_ptr_array;
// filling input array
for(unsigned int i = 0; i < ip_size; i++)
{
ip_ptr_array[i] = i+2*2;
}
// function calling to get output data
algo_fun(ip_ptr_array,
ip_size,
&op_ptr_array,
&op_size);
delete [] ip_ptr_array;
delete [] op_ptr_array;
return 0;
}
将找到工作版本 here。
用于测试的命令: valgrind --leak-check=full --show-leak-kinds=all -v ./file
Leak Summary from valgrind
==23138== LEAK SUMMARY:
==23138== definitely lost: 0 bytes in 0 blocks
==23138== indirectly lost: 0 bytes in 0 blocks
==23138== possibly lost: 0 bytes in 0 blocks
==23138== still reachable: 72,704 bytes in 1 blocks
==23138== suppressed: 0 bytes in 0 blocks
==23138==
==23138== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==23138== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
tl;dr 请检查您使用的是不是最新的 Valgrind。
结合使用 Valgrind 和 gdb,您应该能够看到发生了什么。
我得到以下信息(FreeBSD 12.2、g++ 10.3.0、从 git HEAD 构建的 Valgrind,[OS 和编译器版本不相关])。我正在使用 --trace-malloc=yes
选项查看所有 mallloc/free 调用。不要在大型应用程序上这样做。
$ valgrind --leak-check=full --trace-malloc=yes ./test
--61886-- malloc(72704) = 0x5800040
--61886-- calloc(1984,1) = 0x5811C80
--61886-- calloc(104,1) = 0x5812480
--61886-- calloc(224,1) = 0x5812530
--61886-- calloc(80,1) = 0x5812650
--61886-- calloc(520,1) = 0x58126E0
--61886-- calloc(88,1) = 0x5812930
--61886-- _Znam(40) = 0x58129D0
--61886-- _Znam(48) = 0x5812A40
--61886-- _ZdaPv(0x58129D0)
--61886-- _ZdaPv(0x5812A40)
--61886-- free(0x5800040)
==61886==
==61886== HEAP SUMMARY:
==61886== in use at exit: 3,000 bytes in 6 blocks
==61886== total heap usage: 9 allocs, 3 frees, 75,792 bytes allocated
_Znam 是 array new 的错位版本,_ZdaPv 是代码中 array delete 的错位版本。对 malloc/calloc/free 的其他调用来自 libc/libstc++。您可能会在 Linux 或 libc++ 上看到不同的痕迹。
您可以使用 --show-reachable=yes
获取有关可用内存的信息。
如果我现在运行在gdb下
$ gdb ./test
(gdb) b malloc
(gdb) b malloc
(gdb) r
Breakpoint 1, malloc (nbytes=96) at /usr/src/libexec/rtld-elf/rtld.c:5877
这是对 link 加载程序 ld.so 中的 malloc 的调用。然后我又执行了几个'r'直到
Breakpoint 1, __je_malloc_initialized () at jemalloc_jemalloc.c:208
此处 link 加载程序已加载 libstdc++.so 并且全局 malloc 已被 jemalloc 替换。
获取调用堆栈
(gdb) bt
#0 __je_malloc_initialized () at jemalloc_jemalloc.c:208
#1 imalloc (sopts=<optimized out>, dopts=<optimized out>) at jemalloc_jemalloc.c:1990
#2 __malloc (size=72704) at jemalloc_jemalloc.c:2042
#3 0x00000008006eb6f4 in ?? () from /usr/local/lib/gcc10/libstdc++.so.6
#4 0x000000080060e2fd in objlist_call_init (list=<optimized out>, lockstate=<optimized out>) at /usr/src/libexec/rtld-elf/rtld.c:2820
#5 0x000000080060d03d in _rtld (sp=0x7fffffffe408, exit_proc=0x7fffffffe3d0, objp=0x7fffffffe3d8) at /usr/src/libexec/rtld-elf/rtld.c:811
#6 0x000000080060a8c9 in rtld_start () at /usr/src/libexec/rtld-elf/amd64/rtld_start.S:39
#7 0x0000000000000000 in ?? ()
(gdb)
注意第 #2
行的相同分配大小。
我不打算深入研究这个内存的用途,它是 C++ 运行time 的一部分。
libstdc++(和 libc)故意不释放此内存(大概这很难或不值得)。为了过滤掉这些分配,Valgrind 使用一个特殊函数要求 libstc++/libc 释放这些内存。
本例中的选项是
--run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux
(严格来说,不仅仅是Linux)。
查看 Valgrind 发行说明
Release 3.12.0 (20 October 2016)
...
* New option --run-cxx-freeres=<yes|no> can be used to change whether
__gnu_cxx::__freeres() cleanup function is called or not. Default is
'yes'.
所以我假设您使用的是 3.11 或更早版本。
最后,如果我使用 clang++/libc++,则没有 运行时间分配(也没有 freeres 函数)。