为什么 malloc(0) 在 Windows 上会导致严重的内存泄漏?
Why does malloc(0) cause a major memory leak on Windows?
我刚刚结束了愉快的 4.5 小时调试系统中的严重泄漏。
原来我是这样做的:
params = allocate(sizeof(Something*) * num_params);
这实际上是调用 malloc
并传入第一个参数。当 num_params
为 0 时,它将调用 malloc(0)
.
运行这是一个循环,程序会很快占用大部分内存。我通过首先检查是否 num_params == 0
来修复它,如果是,则避免调用 allocate
.
我知道标准规定 malloc(0)
是实现定义的。那么,这在Windows 7 C 运行时库中是如何实现的,为什么会导致泄漏?
编辑: 澄清问题 - 为什么 Windows 上的 malloc(0)
分配内存,以及决定分配多少内存的逻辑是什么?
malloc(0)
returns 一个新的有效地址,因为这是它在 C 标准允许的选项中选择的选项。
7.22.3 Memory management functions (emphasis mine)
1 The order and contiguity of storage allocated by successive calls
to the aligned_alloc, calloc, malloc, and realloc functions is
unspecified. The pointer returned if the allocation succeeds is
suitably aligned so that it may be assigned to a pointer to any type
of object with a fundamental alignment requirement and then used to
access such an object or an array of such objects in the space
allocated (until the space is explicitly deallocated). The lifetime of
an allocated object extends from the allocation until the
deallocation. Each such allocation shall yield a pointer to an
object disjoint from any other object. The pointer returned points
to the start (lowest byte address) of the allocated space. If the
space cannot be allocated, a null pointer is returned. If the size
of the space requested is zero, the behavior is
implementation-defined: either a null pointer is returned, or the
behavior is as if the size were some nonzero value, except that the
returned pointer shall not be used to access an object.
windows 上的实现选择了第二种行为。所以它必须做 some 分配以确保需求紧接出现在之前。分配函数返回的每个有效指针必须与分配函数返回的任何其他指针不相交。
相关阅读:
- Why is the return value of malloc(0) implementation-defined?
一些系统只是 return NULL
而没有分配任何东西。但是 malloc
分配一个 0 字节的内存块和 return 一个指向该内存的指针是完全合法的。必须像 malloc
.
分配的任何其他块一样释放此块
分配内存时,会涉及一定的开销。所以即使分配0字节也会占用内存
此外,系统可能会过度分配或具有对齐限制,这可能会导致某些内存在每次分配后无法使用。这可能会也可能不会发生在这里。
在评论中,您提到您正在按照以下方式进行操作:
if (num_params > 0) {
...free elements of params...
free(params);
}
相反,您应该一直在执行以下操作:
if (params) {
...free elements of params...
free(params);
}
来自 man 页面:
If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item
并且,通过 valgrind 检查小程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = malloc(0);
if(!p) {
printf("%p\n", p);
}
//free(p);
return 0;
}
我们有日志:
HEAP SUMMARY:
==11874== in use at exit: 0 bytes in 1 blocks
==11874== total heap usage: 1 allocs, 0 frees, 0 bytes allocated
==11874==
==11874== 0 bytes in 1 blocks are definitely lost in loss record 1 of 1
==11874== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
但是用free
函数:
HEAP SUMMARY:
==11887== in use at exit: 0 bytes in 0 blocks
==11887== total heap usage: 1 allocs, 1 frees, 0 bytes allocated
==11887==
==11887== All heap blocks were freed -- no leaks are possible
正如其他人所引用的那样,malloc(0) 是实现定义的,返回空指针或者行为就像大小是某个非零值一样。显然这是第二个选项并引用 Microsoft 的 malloc
文档
If size is 0, malloc allocates a zero-length item in the heap and
returns a valid pointer to that item.
未指定开销。
为了理解,我们可以查看 malloc.c
的 glibc 实现
Even a request for zero bytes (i.e., malloc(0)) returns a pointer
to something of the minimum allocatable size
Minimum allocated size:
4-byte ptrs: 16 bytes (including 4 overhead)
8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
我刚刚结束了愉快的 4.5 小时调试系统中的严重泄漏。
原来我是这样做的:
params = allocate(sizeof(Something*) * num_params);
这实际上是调用 malloc
并传入第一个参数。当 num_params
为 0 时,它将调用 malloc(0)
.
运行这是一个循环,程序会很快占用大部分内存。我通过首先检查是否 num_params == 0
来修复它,如果是,则避免调用 allocate
.
我知道标准规定 malloc(0)
是实现定义的。那么,这在Windows 7 C 运行时库中是如何实现的,为什么会导致泄漏?
编辑: 澄清问题 - 为什么 Windows 上的 malloc(0)
分配内存,以及决定分配多少内存的逻辑是什么?
malloc(0)
returns 一个新的有效地址,因为这是它在 C 标准允许的选项中选择的选项。
7.22.3 Memory management functions (emphasis mine)
1 The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
windows 上的实现选择了第二种行为。所以它必须做 some 分配以确保需求紧接出现在之前。分配函数返回的每个有效指针必须与分配函数返回的任何其他指针不相交。
相关阅读:
- Why is the return value of malloc(0) implementation-defined?
一些系统只是 return NULL
而没有分配任何东西。但是 malloc
分配一个 0 字节的内存块和 return 一个指向该内存的指针是完全合法的。必须像 malloc
.
分配内存时,会涉及一定的开销。所以即使分配0字节也会占用内存
此外,系统可能会过度分配或具有对齐限制,这可能会导致某些内存在每次分配后无法使用。这可能会也可能不会发生在这里。
在评论中,您提到您正在按照以下方式进行操作:
if (num_params > 0) {
...free elements of params...
free(params);
}
相反,您应该一直在执行以下操作:
if (params) {
...free elements of params...
free(params);
}
来自 man 页面:
If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item
并且,通过 valgrind 检查小程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = malloc(0);
if(!p) {
printf("%p\n", p);
}
//free(p);
return 0;
}
我们有日志:
HEAP SUMMARY:
==11874== in use at exit: 0 bytes in 1 blocks
==11874== total heap usage: 1 allocs, 0 frees, 0 bytes allocated
==11874==
==11874== 0 bytes in 1 blocks are definitely lost in loss record 1 of 1
==11874== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
但是用free
函数:
HEAP SUMMARY:
==11887== in use at exit: 0 bytes in 0 blocks
==11887== total heap usage: 1 allocs, 1 frees, 0 bytes allocated
==11887==
==11887== All heap blocks were freed -- no leaks are possible
正如其他人所引用的那样,malloc(0) 是实现定义的,返回空指针或者行为就像大小是某个非零值一样。显然这是第二个选项并引用 Microsoft 的 malloc
文档If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item.
未指定开销。
为了理解,我们可以查看 malloc.c
的 glibc 实现Even a request for zero bytes (i.e., malloc(0)) returns a pointer to something of the minimum allocatable size
Minimum allocated size:
4-byte ptrs: 16 bytes (including 4 overhead)
8-byte ptrs: 24/32 bytes (including, 4/8 overhead)