我知道如何使用malloc()
和free()
来分配内存,但是否也有一种标准的C函数可以检查剩余多少内存,以便我可以定期调用它来确保我的代码没有内存泄漏?
我唯一能想到的是在一个无限循环中调用malloc(1)
直到返回错误,但这难道不应该有更高效的方法吗?
我知道如何使用malloc()
和free()
来分配内存,但是否也有一种标准的C函数可以检查剩余多少内存,以便我可以定期调用它来确保我的代码没有内存泄漏?
我唯一能想到的是在一个无限循环中调用malloc(1)
直到返回错误,但这难道不应该有更高效的方法吗?
Linux glibc sysconf(_SC_AVPHYS_PAGES)
和get_avphys_pages()
这两个glibc扩展可以为您提供可用页面的数量。然后,我们只需将其乘以页面大小sysconf(_SC_PAGESIZE)
,就可以找到总可用内存大小(以字节为单位)。
main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/sysinfo.h>
#include <unistd.h>
int main(void) {
/* PAGESIZE is POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/
* but PHYS_PAGES and AVPHYS_PAGES are glibc extensions. I bet those are
* parsed from /proc/meminfo. */
printf(
"sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)
);
printf(
"sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE)
);
/* glibc extensions. man says they are parsed from /proc/meminfo. */
printf(
"get_phys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
get_phys_pages() * sysconf(_SC_PAGESIZE)
);
printf(
"get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
get_avphys_pages() * sysconf(_SC_PAGESIZE)
);
}
编译和运行:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
我在我的32GiB RAM系统上获得了以下示例输出:
sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x7CCFFC000
sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x6383FD000
get_phys_pages() * sysconf(_SC_PAGESIZE) = 0x7CCFFC000
get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x6383FD000
0x7CCFFC000 是总内存大小,略小于32GiB。0x6383FD000 是可用内存大小。
man get_avphys_pages
表示该命令从 /proc/meminfo
中获取数据。
在 Ubuntu 19.04 中进行测试。
malloc
和free
,从您的起始点递减和递增,正如loreb在另一个答案中建议的那样。 - Alex Reynolds如果你的系统中malloc()
总是分配物理内存,你可以连续调用malloc()
来分配大小不仅相差1,而是连续2的幂次方。这样会更有效率。以下是如何做到的示例。
另一方面,如果malloc()
只分配虚拟地址空间而不映射物理内存,则无法得到预期结果。
示例代码:
#include <stdio.h>
#include <stdlib.h>
void* AllocateLargestFreeBlock(size_t* Size)
{
size_t s0, s1;
void* p;
s0 = ~(size_t)0 ^ (~(size_t)0 >> 1);
while (s0 && (p = malloc(s0)) == NULL)
s0 >>= 1;
if (p)
free(p);
s1 = s0 >> 1;
while (s1)
{
if ((p = malloc(s0 + s1)) != NULL)
{
s0 += s1;
free(p);
}
s1 >>= 1;
}
while (s0 && (p = malloc(s0)) == NULL)
s0 ^= s0 & -s0;
*Size = s0;
return p;
}
size_t GetFreeSize(void)
{
size_t total = 0;
void* pFirst = NULL;
void* pLast = NULL;
for (;;)
{
size_t largest;
void* p = AllocateLargestFreeBlock(&largest);
if (largest < sizeof(void*))
{
if (p != NULL)
free(p);
break;
}
*(void**)p = NULL;
total += largest;
if (pFirst == NULL)
pFirst = p;
if (pLast != NULL)
*(void**)pLast = p;
pLast = p;
}
while (pFirst != NULL)
{
void* p = *(void**)pFirst;
free(pFirst);
pFirst = p;
}
return total;
}
int main(void)
{
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
return 0;
}
输出 (ideone):
Total free: 266677120
Total free: 266673024
Total free: 266673024
Total free: 266673024
Total free: 266673024
我搜索并找到了这个问题,以帮助我制作一个应用程序,在多个复杂值数组中动画多次迭代的分形函数。
谢谢Alexey Frunze提供的ideone.c代码。它确实很有帮助。
在此基础上,为了更加有益,我编写了以下内容:
/* File: count-free-blocks.c
*
* Revision: 2018-24-12
*
* Copyright (C) Randall Sawyer
* <https://stackoverflow.com/users/341214/randall-sawyer>
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
size_t available_blocks (size_t block_sz);
size_t largest_n_blocks (size_t block_sz);
size_t try_alloc (size_t n_blocks,
size_t block_sz);
void report (int indent,
const char *format,
...);
int main (int argc, const char **argv)
{
size_t n_blocks,
block_sz = 0;
if (argc > 1 && sscanf (argv[1], "%zu", &block_sz) != 1)
report (0, "Argument `%s' is not a valid block size.", argv[1]);
if (block_sz == 0)
{
report (0, "Using 1 byte block size...");
block_sz = 1;
}
n_blocks = available_blocks (block_sz);
report (0, "Available memory: %zu blocks of %zu bytes == %zu bytes",
n_blocks, block_sz, n_blocks * block_sz);
return 0;
}
size_t
available_blocks (size_t block_sz)
{
size_t n_blocks[2];
report (0, "calculating free memory...");
/* Calculate maximum number of blocks of given size which can be
* repeatedly allocated.
*/
do {
for ( n_blocks[0] = largest_n_blocks (block_sz);
(n_blocks[1] = largest_n_blocks (block_sz)) < n_blocks[0];
n_blocks[0] = n_blocks[1] );
report (1, "check once more...");
} while (try_alloc (n_blocks[0], block_sz) != n_blocks[0]);
return n_blocks[0];
}
size_t
largest_n_blocks (size_t block_sz)
{
static
const char *f = "phase %d";
size_t n_blocks, max, bit;
report (1, "calculating largest number of free blocks...");
/* Phase 1:
*
* Find greatest allocatable number-of-blocks such that
* it has only one bit set at '1' and '0' for the rest.
*/
report (2, f, 1);
n_blocks = ~(UINTPTR_MAX >> 1); // only MSB is set
max = UINTPTR_MAX / block_sz; // maximimum number of blocks
while (n_blocks && !(n_blocks & max))
n_blocks >>= 1;
while (try_alloc (n_blocks, block_sz) != n_blocks)
n_blocks >>= 1;
/* Phase 2:
*
* Starting with first allocatable number-of-blocks, add decreasingly
* significant bits to this value for each successful allocation.
*/
report (2, f, 2);
for ( bit = n_blocks >> 1; bit; bit >>= 1)
{
size_t n = n_blocks | bit;
if (try_alloc (n, block_sz) == n)
n_blocks = n;
}
/* Phase 3:
* For as long as allocation cannot be repeated,
* decrease number of blocks.
*/
report (2, f, 3);
while (try_alloc (n_blocks, block_sz) != n_blocks)
--n_blocks;
report (1, "free blocks: %zu", n_blocks);
return n_blocks;
}
size_t
try_alloc (size_t n_blocks,
size_t block_sz)
{
if (n_blocks != 0)
{
/* Try to allocate all of the requested blocks.
* If successful, return number of requested blocks;
* otherwise, return 0.
*/
void *p = calloc (n_blocks, block_sz);
report (3, "try %zu blocks of %zu bytes: %s",
n_blocks, block_sz, p ? "success" : "failure");
if (p)
{
free (p);
return n_blocks;
}
}
return 0;
}
#define MAX_INDENT 8
#define INDENT_SPACES " "
void
report (int indent,
const char *format,
...)
{
const char padding[MAX_INDENT+1] = INDENT_SPACES;
va_list args;
if (indent > MAX_INDENT)
indent = MAX_INDENT;
if (indent > 0)
printf ("%s", &padding[8-indent]);
va_start (args, format);
vprintf (format, args);
va_end (args);
printf ("\n");
}
用法:
count-free-blocks [BLOCK_SIZE]
输入:
> ./count-free-blocks 33554432
输出:
calculating free memory...
calculating largest number of free blocks...
phase 1
try 64 blocks of 33554432 bytes: success
phase 2
try 96 blocks of 33554432 bytes: failure
try 80 blocks of 33554432 bytes: success
try 88 blocks of 33554432 bytes: success
try 92 blocks of 33554432 bytes: failure
try 90 blocks of 33554432 bytes: success
try 91 blocks of 33554432 bytes: success
phase 3
try 91 blocks of 33554432 bytes: success
free blocks: 91
calculating largest number of free blocks...
phase 1
try 64 blocks of 33554432 bytes: success
phase 2
try 96 blocks of 33554432 bytes: failure
try 80 blocks of 33554432 bytes: success
try 88 blocks of 33554432 bytes: success
try 92 blocks of 33554432 bytes: failure
try 90 blocks of 33554432 bytes: success
try 91 blocks of 33554432 bytes: success
phase 3
try 91 blocks of 33554432 bytes: success
free blocks: 91
check once more...
try 91 blocks of 33554432 bytes: success
Available memory: 91 blocks of 33554432 bytes == 3053453312 bytes
我打算将这些函数重新用于我的应用程序。
malloc
都会保留一部分虚拟地址空间,因此最终会返回错误。 - Fred Foo