我知道如何使用
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 稍小,是总 RAM。 0x6383FD000 是可用的。
man get_avphys_pages
表示它从 /proc/meminfo
获取数据。
在 Ubuntu 19.04 中测试。
_CrtSetDbgFlag
始终分配物理内存,您可以重复调用
malloc()
,其大小不是相差 1,而是相差 2 的连续幂。这样效率会更高。以下是如何操作的示例。另一方面,如果
malloc()
只分配虚拟地址空间而不将物理内存映射到其中,这不会给你你想要的。
示例代码:
malloc()
输出(ideone
):
#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;
}
标准技巧是分配比请求更多的 sizeof(size_t) ,从而将大小与新分配的内存存储在一起 - 但如果您正在编写固件,我想您已经知道了:)
那么...你有模拟器吗?
编辑:我已经习惯了以 GHz 运行的计算机,一开始我并没有想到这一点,但当然你可以做的另一件事是只计算分配的数量,而不是它们的大小 - 我不能想象一下这会如何占用太多内存来运行。
谢谢 Alexey Frunze 提供的 ideone.c 代码。这确实很有帮助。
根据我所学到的知识,为了更多的帮助,我写了以下内容:
Total free: 266677120
Total free: 266673024
Total free: 266673024
Total free: 266673024
Total free: 266673024
用途:
计数空闲块 [
BLOCK_SIZE]
输入:
/* 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 33554432
我打算将这些函数重新用于我自己的应用程序中。