内存管理- C -检查当前可用的空闲RAM



我知道如何使用malloc()free()来分配内存,但是也有一个标准的C函数来检查剩下多少内存,所以我可以定期调用它来确保我的代码没有内存泄漏?

我唯一能想到的是调用malloc(1)在一个无限循环,直到它返回一个错误,但不应该有一个更有效的方式?

Linux glibc sysconf(_SC_AVPHYS_PAGES)get_avphys_pages()

这两个glibc扩展应该为您提供可用的页面数。然后,我们只需将其乘以页面大小sysconf(_SC_PAGESIZE)就可以找到以字节为单位的总可用内存。

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%lXn",
        sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)
    );
    printf(
        "sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lXn",
        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%lXn",
        get_phys_pages() * sysconf(_SC_PAGESIZE)
    );
    printf(
        "get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x%lXn",
        get_avphys_pages() * sysconf(_SC_PAGESIZE)
    );
}

GitHub上游。

编译并运行:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

示例输出在我的32gb 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获取数据。

不,没有标准的C函数可以做到这一点。您可以使用一些特定于平台的函数来执行某些类型的查询(如工作集大小),但这些函数可能不会有帮助,因为有时已经正确地free() d的内存仍然被认为是由操作系统分配的,因为malloc实现可能会将释放的内存保留在池中。

如果你想检查内存泄漏,我强烈建议使用像Valgrind这样的工具,它可以在虚拟机中运行你的程序,并且可以跟踪内存泄漏,以及其他功能。

如果你在Windows上运行,你可以使用_CrtDbgReport和/或_CrtSetDbgFlag来检查内存泄漏

如果在您的系统中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: %zun", GetFreeSize());
  printf("Total free: %zun", GetFreeSize());
  printf("Total free: %zun", GetFreeSize());
  printf("Total free: %zun", GetFreeSize());
  printf("Total free: %zun", GetFreeSize());
  return 0;
}
输出(ideone):

Total free: 266677120
Total free: 266673024
Total free: 266673024
Total free: 266673024
Total free: 266673024

如果你能负担得起#ifdef调试版本(可能在模拟器中!),你可以构建一个malloc/free的调试版本,跟踪当前使用的字节数,并定期"打印"它(再次-仅在调试版本中,可能在模拟器下)在任何输出设备上调试(led?),看看它是否不断增加。

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

所以…你有模拟器吗?

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

我搜索并发现了这个问题,以帮助我制作一个应用程序,在多个复杂值数组上动画分形函数的多次迭代。

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

用法:

(<<p> count-free-blocks em> 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

我打算在我自己的应用程序中重新使用这些函数

相关内容

  • 没有找到相关文章

最新更新