50-процентное правило

#c #malloc #free

#c #malloc #Бесплатно

Вопрос:

Я пишу программу, которая проверяет динамическое распределение памяти, чтобы увидеть, насколько хорошо выполняется правило 50 процентов.

Программа содержит 10000 указателей на динамически выделяемые блоки памяти. В нем также есть массив для хранения размера каждого блока. Это должно:

  1. Используется malloc() для динамического выделения блока памяти для каждого элемента ptrList . Эти блоки должны иметь размеры, которые выбираются случайным образом в диапазоне от 1 до 10000 байт, и размер блока должен храниться в 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 %dn", j, maximum - minimum, total);
      }

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

  }

  return 0;
}
  

Правильно ли я подхожу к выделению / освобождению памяти? Моя программа компилируется и запускается (без вывода) до того, как я внедрил for цикл с int j помощью. Оно зависает после того, как я его внедрил, поэтому, возможно, кто-нибудь сможет помочь мне устранить проблему и там.

Редактировать: Правило 50 процентов заключается в том, что общий размер всех блоков, деленный на приблизительный размер кучи, обычно будет составлять около 50 процентов.

Комментарии:

1. «Оно зависает после того, как я его внедрил» — это обычно считается проблемой…

2. @MitchWheat Да, я не совсем уверен, что является причиной этого. Комментирование for (int j = 0; j < 1000; j ) позволяет программе выполняться до завершения. Как только я снова комментирую эту строку, программа зависает. Я также пробовал добавлять for цикл для освобождения памяти в конце каждой итерации.

3. К вашему сведению, случайные распределения и освобождения исторически были очень плохой моделью использования памяти программ. Не так много твердых выводов вы можете сделать из такого эксперимента. Вы можете получить более интересные данные, заменив свой распределитель в паре больших процессов — таких как веб-браузер (который выполняется непрерывно) или компилятор (который завершается после обработки файла).

4. Это зависает или это занимает много времени? Вы должны заставить его печатать сообщения о ходе выполнения. Вы должны проверить результат malloc на null.

5. Мне также любопытно, что вы подразумеваете под «правилом 50 процентов». Если вы имеете в виду, что 50 процентов памяти кучи будет занято при номинальном заполнении, это будет свидетельствовать о довольно плохом менеджере кучи.

Ответ №1:

Помимо cruft (вопиюще ненужный код) у вас есть некоторые проблемы с переменными и циклами: ваш for (int i = 0; i < TEST_LENGTH; i )... цикл, который реализует шаг 2 спецификации, является циклом, в рамках которого каждые 100 шагов вы должны печатать текущую статистику. Наличие внешнего for (int j = 0; j < 1000; j ) цикла и тестирование j0 остатков — это бессмыслица.

Для отладки подобной проблемы уберите два или три нуля с каждого из больших чисел BLOCK_COUNT, TEST_LENGTH, SIZE_LIMIT, измените j ограничение цикла на 10 и добавьте printf("j=..." ...) after for (int j ...) { , чтобы вы могли сказать, что происходит. С такими изменениями вы увидите:

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

и тогда можно сделать вывод, что ваша программа, казалось, зависала, потому что она медленно считала j до 100, чтобы добраться до j0 == 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 amp;amp; j%100 == 0 ) {
     ...
  

Основная проблема с вашей программой: когда вы говорите free(ptrList[index]); в части 2, вы, возможно, освобождаете элемент, на который приходится текущий минимальный или максимальный адреса памяти. Один из способов решить эту проблему — поддерживать приоритетные очереди со значениями min / max, а также дисциплину fifo; я думаю, что вам будет проще не отслеживать min / max при распределении, а вместо этого просто иметь цикл для поиска min / max непосредственно перед каждой распечаткой.

Небольшая проблема с вашей программой: максимальный используемый адрес указан не ptrList[index] для некоторого индекса, а ptrList[index] sizeList[index] .

Комментарии:

1. Спасибо, у меня изначально было if (j == 0 || j0 == 0) , но программе это не понравилось. Я постараюсь просмотреть свой код и удалить как можно больше мусора, но прямо сейчас я застрял на минимальной проблеме. SIZE_LIMIT ограничен 10000, и размеры кучи должны быть намного больше, чем это, чтобы max - min находиться в 98,000,000 диапазоне. Запустив мою программу несколько раз, максимальный размер кучи изменяется, как и должно быть, но минимальный размер кучи остается прежним, и я, похоже, не могу точно определить, где кроется ошибка в моей логике.

2. Возможно, вы написали этот комментарий, когда я редактировал со 2-го по последний абзац, с минимальными / максимальными проблемами. Re «SIZE_LIMIT ограничен …» просто измените константы на те, с которыми легко работать во время отладки, например, выполните только 3 или 4 прохода с полудюжиной многомегабайтных блоков, чтобы вы могли распечатать все размеры и проверить вручную; когда все это сработает, исправьте константы на требуемые значения.

3. Спасибо, я удалил поиск min и max непосредственно перед печатью. У меня все еще возникают проблемы с minimum тем, чтобы оставаться прежним. Возможно, я неправильно рассчитываю минимум? Является ли дробный размер кучи (максимальный — минимальный) / общим? Максимальные значения, кажется, в порядке, но я не могу проверить другие значения.

4. Если память выделяется из набора смежных страниц реальной памяти в однопользовательской системе, я бы ожидал, что доля будет равна total / (max-min). Но когда выделяются страницы из виртуальной памяти, которые могут находиться где угодно, в многопользовательской системе среди других процессов, также выделяющих память, этого не должно быть. Вы пишете код для курса по операционной системе и хотите изучить детали распределения? Или это для курса C?