我有以下代码:
#include <stdlib.h>
#include <stdio.h>
int main() {
void* a = malloc(10);
printf("%p\n", a);
}
编译并运行时:
clang-19 -std=c23 -fsanitize=address -g -Weverything -o test_mem.exe test_mem.c
./test_mem.exe
0x502000000010
=================================================================
==212167==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 10 byte(s) in 1 object(s) allocated from:
#0 0x55f0442625cf in malloc (/home/xxx/xxx/xxx/test_mem.exe+0xcb5cf) (BuildId: fe83f3b1cd62d6171e5d431d34ee529cce48f18f)
#1 0x55f0442a2a68 in main /xxx/xxx/xxx/xxx/test_mem.c:8:11
#2 0x7fa09f96fd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: 10 byte(s) leaked in 1 allocation(s).
检测到内存泄漏。太棒了!
但是,如果我将代码更改为:
#include <stdio.h>
#include <stdlib.h>
void* a = nullptr;
int main() {
a = malloc(10);
printf("%p\n", a);
}
并编译/运行:
clang-19 -std=c23 -fsanitize=address -g -Weverything -o test_mem.exe test_mem.c
... compiler complains about `int* a` not being static, fine...
./test_mem.exe
0x502000000010
未检测到内存泄漏。执行此int* a
static
操作不会改变此行为(编译器只是将其报告为警告)。
我确信有一个“充分的理由”来解释为什么全局声明变量时不会报告内存泄漏,但是:
为什么会这样?这种行为有具体的原因吗?当在全局范围内声明变量时,即使是动态分配的,其内存也会自动释放吗?如果是这样,是否意味着释放该内存(例如执行 free(a))不是绝对必要的?
有没有办法配置清理器或编译器来检测全局变量的内存泄漏?也许一些标志?
如果在分配的内存块的生命周期结束之前(即,在将指针传递给之前),指向该内存块的所有指针都丢失,则会发生内存泄漏
free
。如果这样的指针存储在全局变量中,或者更准确地说,存储在文件范围的变量中,其生存期是整个程序的生存期,那么指向分配内存的指针在程序的生存期内永远不会丢失,因此不会发生内存泄漏。
像 valgrind 这样的工具(在运行时检查行为)会注意到类似的情况,表明分配的内存“仍然可达”而不是泄漏。
该代码的 valgrind 输出如下: