【问题标题】:50-Percent Rule50% 规则
【发布时间】:2011-11-08 01:44:02
【问题描述】:

我正在编写一个测试动态内存分配的程序,以了解 50% 规则的适用程度。

该程序有 10,000 个指向动态分配的内存块的指针。它还有一个数组来存储每个块的大小。它应该:

  1. 使用malloc()ptrList 的每个元素动态分配一块内存。这些块的大小应在 1 到 10,000 字节范围内随机选择,并且块大小应存储在 sizeList 数组中。
  2. 初始块分配后,程序应反复释放块并分配新块。这应该循环 100,000 次迭代。在每次迭代中,随机选择ptrList 中的索引,释放该块,然后替换为具有随机大小的新动态分配块。
  3. 每 100 次迭代后,它应该打印出一行,显示迭代计数、近似堆大小(由任何块中包含的最高和最低内存地址之间的差异确定)以及所有块的总大小ptrList 指向的块。

我的程序编码如下:

#include <stdio.h>
#include <pthread.h>   /* for pthreads */
#include <stdlib.h>    /* for exit */

/** Number of memory blocks to allocate/deallocate. */
#define BLOCK_COUNT 10000

/** Number of free/malloc operations to perform */
#define TEST_LENGTH 100000

/** Maximum size of an allocated block. */
#define SIZE_LIMIT 10000

int main( int argc, char *argv[] ) {
  // Array of pointers to all blocks that have been allocated.
  char *ptrList[ BLOCK_COUNT ];

  // Array of sizes for each block, so we can know how much memory we're using.
  int sizeList[ BLOCK_COUNT ];

  // Insert your code here
  for (int j = 0; j < 1000; j++) {

      int minimum = 0;
      int maximum = 0;
      int total = 0, remainder = 0;

      for (int i = 0; i < BLOCK_COUNT; i++) {
          int size = (rand() % SIZE_LIMIT) + 1;
          ptrList[i] = malloc (size);
          sizeList[i] = size;
          total += size;
          int heapsize = (int)ptrList[i];

          if (i == 0) {
              maximum = heapsize;
              minimum = heapsize;
          }
          else {
              if (heapsize > maximum) {
                  maximum = heapsize;
              }
              if (heapsize < minimum) {
                  minimum = heapsize;
              }
          }
      }

      for (int i = 0; i < TEST_LENGTH; i++) {
          int index = rand() % BLOCK_COUNT;
          int size = (rand() % SIZE_LIMIT) + 1;
          free(ptrList[index]);
          total -= sizeList[index];
          ptrList[index] = malloc (size);
          sizeList[index] = size;
          total += sizeList[index];
          int heapsize = (int)ptrList[index];

          if (heapsize > maximum) {
              maximum = heapsize;
          }
          if (heapsize < minimum) {
              minimum = heapsize;
          }
      }

      if (j > 0) {
          remainder = j % 100;
      }

      if (remainder == 0 ) {
          //printf("%d", example);
          printf("%d %d %d\n", j, maximum - minimum, total);
      }

      for (int i = 0; i < BLOCK_COUNT; i++) {
          free(ptrList[i]);
      }

  }

  return 0;
}

我是否以正确的方式处理内存的分配/解除分配?在我用int j 实现for 循环之前,我的程序编译并运行(没有输出)。在我实施后它挂起,所以也许有人可以帮我解决问题。

编辑: 50% 规则是所有块的总大小除以堆大小的近似值,通常约为 50%。

【问题讨论】:

  • “我实现它后它挂起” - 这通常被认为是一个问题......
  • @MitchWheat 是的,我不太确定是什么原因造成的。注释掉for (int j = 0; j &lt; 1000; j++) 允许程序运行完成。一旦我重新评论该行,程序就会挂起。我也尝试在每次迭代结束时添加一个for 循环来释放内存。
  • 仅供参考,随机分配和释放一直是程序内存使用的非常糟糕的模型。您可以从这样的实验中得出的可靠结论并不多。通过将分配器替换为几个大进程,您可能会获得更有趣的数据——例如 Web 浏览器(连续运行)或编译器(在处理文件后结束)。
  • 它挂起,还是需要很长时间?您应该让它打印进度消息。您应该检查 malloc 的结果是否为 null。
  • 我也很好奇您所说的“50% 规则”是什么意思。如果您的意思是 50% 的堆内存在名义上已满时会被占用,那将证明堆管理器相当糟糕。

标签: c malloc free


【解决方案1】:

除了杂乱无章(非常不必要的代码)之外,您还遇到了一些变量和循环问题:您的 for (int i = 0; i &lt; TEST_LENGTH; i++)... 循环实现了规范的第 2 步,是一个循环,您应该在其中每 100 步打印当前统计信息.有一个外部for (int j = 0; j &lt; 1000; j++) 循环和测试j%100 余数是无稽之谈。

要调试这样的问题,请在每个大数字 BLOCK_COUNT、TEST_LENGTH、SIZE_LIMIT 上敲掉两个或三个零,将 j 循环限制更改为 10,并在 for (int j ...) { 之后添加 printf("j=..." ...),这样您就可以告诉发生了什么。通过这样的更改,您将看到:

  j=0 0 0
  0 556736 507760
  j=1 0 0
  j=2 0 0
  j=3 0 0
  ...

然后可以得出结论,您的程序似乎挂起,因为它正在缓慢地将 j 计数到 100 以到达 j%100 == 0

现在我会提到两个要删除的小问题,然后会提到你的程序的一个主要问题。

代替

  int minimum = 0;
  int maximum = 0;
  ...
     if (i == 0) {
        maximum = heapsize;
        minimum = heapsize;
     }
     else {
       if (heapsize > maximum) {
          maximum = heapsize;
     }
     if (heapsize < minimum) {
          minimum = heapsize;
     }

  int minimum = MAX_INT;
  int maximum = 0;
  ...
     if (heapsize > maximum)
        maximum = heapsize;
     if (heapsize < minimum)
        minimum = heapsize;

(或者可能是 MAX_INT 的变体)和(如果您需要 j 和/或 remainder,您不需要)而不是

  if (j > 0) {
      remainder = j % 100;
  }

  if (remainder == 0 ) {
     ...

你会写

  if (j>0 && j%100 == 0 ) {
     ...

您的程序的一个主要问题:当您在第 2 部分中说 free(ptrList[index]); 时,您可能正在释放占当前最小或最大内存地址的项目。解决此问题的一种方法是维护具有最小/最大值和 fifo 规则的优先级队列;我认为,您会发现更简单的是在分配时不跟踪 min/max,而是在每次打印输出之前有一个循环来查找 min/max。

您的程序的一个小问题:某些索引使用的最大地址不是ptrList[index],而是ptrList[index]+sizeList[index]

【讨论】:

  • 谢谢,我最初有if (j == 0 || j%100 == 0),但程序不喜欢这样。我将尝试检查我的代码并尽可能多地删除垃圾,但现在我被困在最小的问题上。 SIZE_LIMIT 限制为 10000,并且堆大小必须远大于 max - min 才能在 98,000,000 范围内。多次运行我的程序,最大堆大小会发生变化,但最小堆大小保持不变,我似乎无法确定错误在我的逻辑中的位置。
  • 您可能在我编辑第 2 段到最后一段时写了该评论,请注意最小/最大问题。重新“SIZE_LIMIT 仅限于...”只需将常量更改为在调试时易于使用的任何内容,例如只对六个数兆字节块执行 3 或 4 次传递,因此您可以打印所有大小并手动检查;当一切正常时,将常量更正为所需的值。
  • 谢谢,直到打印之前,我已经删除了查找 minmax。我仍然遇到minimum 保持不变的问题。也许我以错误的方式计算最小值?是分数堆大小(最大 - 最小)/总数吗?最大值似乎没问题,但我无法检查其他值。
  • 如果内存是从单用户系统上一组连续的实际内存页面中分配的,我希望分数是总/(最大-最小)。但是,当它被分配到可以在任何地方的虚拟内存页面之外时,在多用户系统上,其他进程也分配内存时,情况就不必如此了。您是否正在为操作系统课程编写代码并想学习分配细节?还是针对 C 课程?
猜你喜欢
  • 2018-04-03
  • 2019-12-18
  • 1970-01-01
  • 2012-01-28
  • 2019-01-15
  • 2020-10-02
  • 1970-01-01
  • 2017-02-16
  • 1970-01-01
相关资源
最近更新 更多