10

malloc()メモリの使用方法と割り当て方法は知ってfree()いますが、残りのメモリ量をチェックする標準のC関数もあるので、定期的に呼び出して、コードにメモリリークがないことを確認できますか?

私が考えることができる唯一のことmalloc(1)は、エラーが返されるまでエンドレスループで呼び出すことですが、より効率的な方法があるべきではありませんか?

4

5 に答える 5

7

いいえ、それを行うための標準のC関数はありません。free()特定のタイプのクエリ(ワーキングセットサイズなど)を実行するために使用できるプラットフォーム固有の関数がいくつかありますが、適切にdされたメモリがOSによって割り当てられていると見なされることがあるため、これらはおそらく役に立たないでしょう。実装によりmalloc、解放されたメモリがプール内に保持される場合があります。

メモリリークをチェックしたい場合は、Valgrindのようなツールを使用することを強くお勧めします。このツールは、ある種の仮想マシンでプログラムを実行し、メモリリークなどの機能を追跡できます。

Windowsで実行している場合は、メモリリークを使用_CrtDbgReportおよび/または_CrtSetDbgFlagチェックできます。

于 2013-01-17T19:47:43.867 に答える
4

システムで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
于 2013-01-18T09:23:14.593 に答える
2

デバッグバージョンを#ifdefする余裕がある場合(おそらくエミュレーターで!)、現在使用されているバイト数を追跡​​するmalloc / freeのデバッグバージョンを作成し、定期的に(再度)「印刷」することができます。 -デバッグ用に使用している出力デバイス(led?)のデバッグバージョン(場合によってはエミュレーターの下)でのみ、増加し続けるかどうかを確認します。

標準的なトリックは、sizeof(size_t)を要求よりも多く割り当てて、新しく割り当てられたメモリと一緒にサイズを保存することです。ただし、ファームウェアを作成している場合は、すでに知っていると思います:)

だから...エミュレータはありますか?

編集:私はGHzで実行されているコンピューターに慣れているので、最初は思いもよらなかったのですが、もちろん、割り当てのサイズではなく、割り当ての数を数えることもできます-想像できませんこれを実行するにはメモリが多すぎる可能性があります。

于 2013-01-17T20:34:14.270 に答える
0

この質問を検索して見つけたのは、複雑な値の複数の配列にわたるフラクタル関数の多数の反復をアニメーション化するアプリケーションを作成するのに役立ちます。

ideone.c コードを提供してくれた Alexey Frunze に感謝します。確かに役に立ちました。

学んだことに基づいて、より役立つことを期待して、次のように書きました。

/* 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

これらの機能を自分のアプリケーションに再利用するつもりです。

于 2018-12-23T20:56:37.423 に答える