C - 检查当前可用的空闲 RAM?

问题描述 投票:0回答:5

我知道如何使用

malloc()
free()
来分配内存,但是是否还有一个标准 C 函数来检查剩余内存量,以便我可以定期调用它以确保我的代码没有内存泄漏?

我唯一能想到的就是无限循环地调用

malloc(1)
,直到返回错误,但是不应该有更有效的方法吗?

c memory-management memory-leaks malloc c99
5个回答
9
投票

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)
    );
}

GitHub 上游.

编译并运行:

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 中测试。


7
投票

不,没有标准的 C 函数可以做到这一点。 您可以使用一些特定于平台的函数来执行某些类型的查询(例如工作集大小),但这些函数可能没有帮助,因为有时已正确分配的内存仍被认为是由操作系统,因为

free()
实现可能会将释放的内存保留在池中。

如果您想检查内存泄漏,我强烈建议使用像

Valgrind

这样的工具,它在某种虚拟机中运行您的程序,并且可以跟踪内存泄漏等功能。 如果您在 Windows 上运行,则可以使用

malloc

 和/或 
_CrtDbgReport
 检查内存泄漏。


4
投票
_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; }



2
投票

标准技巧是分配比请求更多的 sizeof(size_t) ,从而将大小与新分配的内存存储在一起 - 但如果您正在编写固件,我想您已经知道了:)

那么...你有模拟器吗?

编辑:我已经习惯了以 GHz 运行的计算机,一开始我并没有想到这一点,但当然你可以做的另一件事是只计算分配的数量,而不是它们的大小 - 我不能想象一下这会如何占用太多内存来运行。


1
投票

谢谢 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

我打算将这些函数重新用于我自己的应用程序中。

© www.soinside.com 2019 - 2024. All rights reserved.