valgrind --trace-children=yes 报告泄漏尽管 atexit 清理
valgrind --trace-children=yes reports leak despite atexit cleanup
我正在尝试使用 valgrind 避免误报,但尽管使用了 --trace-children=yes
,但我对 atexit()
和 fork()
的组合感到厌烦。我的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int * arr;
static void cleanup() {
free(arr);
printf("free arr as: %p\n", (void *)arr);
}
int main()
{
arr = malloc(16 * sizeof(int));
printf("allocated arr as: %p\n", (void *)arr);
atexit(cleanup);
pid_t pid = fork();
if (pid == -1) {
exit(1);
} else if (pid == 0) {
// child
_exit(0);
} else {
// parent
exit(0);
}
}
命令行:
$ clang -Weverything leak.c
$ valgrind --trace-children=yes ./a.out
==3287== Memcheck, a memory error detector
==3287== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3287== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==3287== Command: ./a.out
==3287==
allocated arr as: 0x5202040
free arr as: 0x5202040
==3288==
==3288== HEAP SUMMARY:
==3288== in use at exit: 64 bytes in 1 blocks
==3288== total heap usage: 2 allocs, 1 frees, 1,088 bytes allocated
==3288==
==3288== LEAK SUMMARY:
==3288== definitely lost: 0 bytes in 0 blocks
==3288== indirectly lost: 0 bytes in 0 blocks
==3288== possibly lost: 0 bytes in 0 blocks
==3288== still reachable: 64 bytes in 1 blocks
==3288== suppressed: 0 bytes in 0 blocks
==3288== Rerun with --leak-check=full to see details of leaked memory
==3288==
==3288== For counts of detected and suppressed errors, rerun with: -v
==3288== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==3287==
==3287== HEAP SUMMARY:
==3287== in use at exit: 0 bytes in 0 blocks
==3287== total heap usage: 2 allocs, 2 frees, 1,088 bytes allocated
==3287==
==3287== All heap blocks were freed -- no leaks are possible
==3287==
==3287== For counts of detected and suppressed errors, rerun with: -v
==3287== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
根据 printf()
输出,看起来没有泄漏。我可以让 valgrind 相信这一点,还是应该将其添加到我的 valgrind 抑制文件中?
Based on the printf() output, it looks like there's no leaks. Can I convince valgrind of this, or should I just add this to my valgrind suppression file?
看来 valgrind 是对的。如果您将 printf()
输出解释为表明没有泄漏,那么您就不会欣赏 fork()
.
的效果
当您分叉一个 child 时,它会得到其 parent 地址 space 的完整副本。这通常通过 copy-on-write 页实现,但它仍然构成属于 child 的内存。在您的情况下,这包括 dynamically-allocated 数组 arr
.
的副本
child 通过调用 _exit()
退出,因此虽然它继承了其 parent 的 exit-handler 注册,但在该进程中不会调用已注册的退出处理程序。你可以这么说,因为你只看到一次 cleanup()
的输出。因此,属于 child 的 arr
副本永远不会被释放,正如 valgrind 告诉您的那样。
不过,将此称为内存泄漏有点迂腐。当程序终止时,有问题的内存仍然可以访问,此时它会被系统回收。它根本没有在终止前显式释放。
您正在子进程中使用 _exit()。根据 _exit 的手册页:
The function _exit() is like exit(3), but does not call any functions registered with atexit(3) or on_exit(3).
改为exit(0)。应该可以。
我正在尝试使用 valgrind 避免误报,但尽管使用了 --trace-children=yes
,但我对 atexit()
和 fork()
的组合感到厌烦。我的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int * arr;
static void cleanup() {
free(arr);
printf("free arr as: %p\n", (void *)arr);
}
int main()
{
arr = malloc(16 * sizeof(int));
printf("allocated arr as: %p\n", (void *)arr);
atexit(cleanup);
pid_t pid = fork();
if (pid == -1) {
exit(1);
} else if (pid == 0) {
// child
_exit(0);
} else {
// parent
exit(0);
}
}
命令行:
$ clang -Weverything leak.c
$ valgrind --trace-children=yes ./a.out
==3287== Memcheck, a memory error detector
==3287== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3287== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==3287== Command: ./a.out
==3287==
allocated arr as: 0x5202040
free arr as: 0x5202040
==3288==
==3288== HEAP SUMMARY:
==3288== in use at exit: 64 bytes in 1 blocks
==3288== total heap usage: 2 allocs, 1 frees, 1,088 bytes allocated
==3288==
==3288== LEAK SUMMARY:
==3288== definitely lost: 0 bytes in 0 blocks
==3288== indirectly lost: 0 bytes in 0 blocks
==3288== possibly lost: 0 bytes in 0 blocks
==3288== still reachable: 64 bytes in 1 blocks
==3288== suppressed: 0 bytes in 0 blocks
==3288== Rerun with --leak-check=full to see details of leaked memory
==3288==
==3288== For counts of detected and suppressed errors, rerun with: -v
==3288== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==3287==
==3287== HEAP SUMMARY:
==3287== in use at exit: 0 bytes in 0 blocks
==3287== total heap usage: 2 allocs, 2 frees, 1,088 bytes allocated
==3287==
==3287== All heap blocks were freed -- no leaks are possible
==3287==
==3287== For counts of detected and suppressed errors, rerun with: -v
==3287== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
根据 printf()
输出,看起来没有泄漏。我可以让 valgrind 相信这一点,还是应该将其添加到我的 valgrind 抑制文件中?
Based on the printf() output, it looks like there's no leaks. Can I convince valgrind of this, or should I just add this to my valgrind suppression file?
看来 valgrind 是对的。如果您将 printf()
输出解释为表明没有泄漏,那么您就不会欣赏 fork()
.
当您分叉一个 child 时,它会得到其 parent 地址 space 的完整副本。这通常通过 copy-on-write 页实现,但它仍然构成属于 child 的内存。在您的情况下,这包括 dynamically-allocated 数组 arr
.
child 通过调用 _exit()
退出,因此虽然它继承了其 parent 的 exit-handler 注册,但在该进程中不会调用已注册的退出处理程序。你可以这么说,因为你只看到一次 cleanup()
的输出。因此,属于 child 的 arr
副本永远不会被释放,正如 valgrind 告诉您的那样。
不过,将此称为内存泄漏有点迂腐。当程序终止时,有问题的内存仍然可以访问,此时它会被系统回收。它根本没有在终止前显式释放。
您正在子进程中使用 _exit()。根据 _exit 的手册页:
The function _exit() is like exit(3), but does not call any functions registered with atexit(3) or on_exit(3).
改为exit(0)。应该可以。