我知道如何使用malloc()
和free()
来分配内存,但是还有一个标准的C函数来检查剩余的内存,所以我可以定期调用它以确保我的代码没有内存泄漏?
我唯一能想到的是在无限循环中调用malloc(1)
,直到它返回错误,但不应该有更有效的方法吗?
答案 0 :(得分:6)
不,没有标准的C函数可以做到这一点。您可以使用某些特定于平台的函数来执行某些类型的查询(例如工作集大小),但这些函数可能没有帮助,因为有时候已经正确free()
d的内存仍然被认为是由操作系统分配,因为malloc
实现可能会将已释放的内存保留在池中。
如果你想检查内存泄漏,我强烈建议使用像Valgrind这样的工具,它可以在各种虚拟机中运行你的程序,并可以跟踪内存泄漏等功能。
如果您在Windows上运行,则可以使用_CrtDbgReport
和/或_CrtSetDbgFlag
来检查内存泄漏。
答案 1 :(得分:2)
如果你能负担#ifdef的调试版本(可能在模拟器中!),你可以构建一个malloc / free的调试版本来跟踪当前使用的字节数,并“打印”它在你调试的任何输出设备(一个led?)上定期(再次 - 仅在调试版本中,可能在模拟器下),看看它是否在不断增加。
标准技巧是分配sizeof(size_t)超过请求的数量,从而将大小与新分配的内存一起存储 - 但如果你正在编写固件,我猜你已经知道了:)
所以......你有一个模拟器吗?
编辑:我已经习惯了以GHz运行的计算机,起初我没有想到它,但当然你可以做的另一件事就是计算分配数量,而不是它们的大小 - 我可以不要想象这可能会花费太多的记忆来运行。
答案 2 :(得分:1)
如果你的系统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
答案 3 :(得分: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中测试。
答案 4 :(得分:0)
我搜索并发现了这个问题,以帮助我制作一个应用程序来对复数个复杂值数组中的分形函数的多次迭代进行动画处理。
谢谢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");
}
用法:
无计数块[ 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
我打算将这些功能重新用于自己的应用程序中。