Очень высокое использование памяти в этих алгоритмах анализа цифр (хэширования) в C

#arrays #c #pointers #memory #hash

#массивы #c #указатели #память #гашиш

Вопрос:

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

Функция анализа цифр 1 (с использованием динамической матрицы)

 int hashUVDigitAnalysis(int len, int value, int numofdigits, int *arr){  int keydigits, *digits = getDigits(value, amp;keydigits);   if(numofdigits gt;= keydigits){  free(digits); // -ATENÇÃO-  return value; //  }else{ // Essa função funciona, mas quando testei com o vetor *arr muito grande, ele rapidamente  int **numqntmatrix = (int **)(malloc(10 * sizeof(int *))); // consumiu maior parte da memória do meu pc, e o computador falhou por  int cont1, cont2, countdigits; // falta de memória. Use essa função apenas para  float *detours = (float *)(malloc(keydigits * sizeof(float))); // testar um único valor (UV).  // Como alternativa, tentei realizar a função abaixo desta, mas a mesma deu o mesmo problema.  for(cont1 = 0; cont1 lt; 10; cont1  ){ //  numqntmatrix[cont1] = (int *)(malloc(keydigits * sizeof(int)));  for(cont2 = 0; cont2 lt; keydigits; cont2  ){  numqntmatrix[cont1][cont2] = 0;  }  }   for(cont1 = 0; cont1 lt; len; cont1  ){  digits = getDigits(arr[cont1], amp;countdigits);  for(cont2 = 0; cont2 lt; keydigits amp;amp; cont2 lt; countdigits; cont2  ){  numqntmatrix[digits[cont2]][cont2]  = 1;  }  }   for(cont1 = 0; cont1 lt; keydigits; cont1  ){  detours[cont1] = 0.0;  }   for(cont1 = 0; cont1 lt; keydigits; cont1  ){  for(cont2 = 0; cont2 lt; 10; cont2  ){  detours[cont1]  = (numqntmatrix[cont2][cont1] - (len / 10.0)) * (numqntmatrix[cont2][cont1] - (len / 10.0));  }  }   for(cont1 = 0; cont1 lt; 10; cont1  ){  free(numqntmatrix[cont1]);  }  free(numqntmatrix);   int *concatenate = (int *)(malloc(numofdigits * sizeof(int)));   for(cont1 = 0; cont1 lt; numofdigits; cont1  ){  cont2 = 0;  concatenate[cont1] = cont2;  for(cont2 = 1; cont2 lt; keydigits; cont2  ){  if(detours[cont2] lt; detours[concatenate[cont1]] amp;amp; detours[cont2] != -1){  concatenate[cont1] = cont2;  }  }  detours[concatenate[cont1]] = -1;  }   digits = getDigits(value, amp;countdigits);  int valueposition = 0;   for(cont1 = 0; cont1 lt; numofdigits; cont1  ){  valueposition  = digits[concatenate[cont1]] * pow(10, cont1);  }   free(detours);  free(digits);   return valueposition;  } }  

Функция анализа цифр 2 (с использованием только массивов)

 int hashQuadraticDigitAnalysis(int len, int value, int numofdigits, int *arr){  int keydigits, *digits = getDigits(value, amp;keydigits);   if(numofdigits gt;= keydigits){  free(digits);  return value;  }else{  int cont1, cont2, countdigits;  int *numbers = (int *)(malloc(10 * sizeof(int)));  float *detours = (float *)(malloc(10 * sizeof(float)));   for(cont1 = 0; cont1 lt; 10; cont1  ){  numbers[cont1] = 0;  detours[cont1] = 0.0;  }   for(cont1 = 0; cont1 lt; 10; cont1  ){  for(cont2 = 0; cont2 lt; len; cont2  ){  digits = getDigits(arr[cont2], amp;countdigits);  if(cont1 lt; countdigits){  numbers[digits[cont1]]  = 1;  }  }  for(cont2 = 0; cont2 lt; 10; cont2  ){  detours[cont1]  = (numbers[cont2] - (len / 10.0)) * (numbers[cont2] - (len / 10.0));  numbers[cont2] = 0;  }  }   int *concatenate = (int *)(malloc(numofdigits * sizeof(int)));   for(cont1 = 0; cont1 lt; numofdigits; cont1  ){  cont2 = 0;  concatenate[cont1] = cont2;  for(cont2 = 1; cont2 lt; keydigits; cont2  ){  if(detours[cont2] lt; detours[concatenate[cont1]] amp;amp; detours[cont2] != -1){  concatenate[cont1] = cont2;  }  }  detours[concatenate[cont1]] = -1;  }   digits = getDigits(value, amp;countdigits);  int valueposition = 0;   for(cont1 = 0; cont1 lt; numofdigits; cont1  ){  valueposition  = digits[concatenate[cont1]] * pow(10, cont1);  }   free(concatenate);  free(detours);  free(digits);   return valueposition;  } }  

getDigits function

 int* getDigits(int value, int *addr_countdigits){  int copyofvalue = value;  *addr_countdigits = 0;   while(copyofvalue != 0){  copyofvalue = copyofvalue / 10;  *addr_countdigits = *addr_countdigits   1;  }   int tmp = *addr_countdigits;  int *array = (int *)(malloc(tmp * sizeof(int)));  copyofvalue = value;   while(copyofvalue gt; 0){  array[tmp - 1] = copyofvalue % 10;  copyofvalue = copyofvalue / 10;  tmp = tmp-1;  }   return array; }  

Главная

 int main(void){  int len = 100000, lenarr = 200000, cont, random, numcolision = 0, pos;   int *randomarr = (int *)(malloc(lenarr * sizeof(int)));   int *hash_division = (int *)(malloc(len * sizeof(int)));   for(cont = 0; cont lt; len; cont  ){  hash_division[cont] = -1;  }   for(cont = 0; cont lt; lenarr; cont  ){  random = (((rand() amp; 255)lt;lt;8 | (rand() amp; 255))lt;lt;8 | (rand() amp; 255))lt;lt;7 | (rand() amp; 127);  random = random % 2000000001;  randomarr[cont] = random;  }   for(cont = 0; cont lt; lenarr; cont  ){  pos = hashUVDigitAnalysis(lenarr, randomarr[cont], 5, randomarr);  if(hash_division[pos] == -1){  hash_division[pos] = randomarr[cont];  } else{  numcolision  ;  }  }   printf("%d", numcolision);  return 0; }  

У меня есть 14 ГБ полезной оперативной памяти (всего 16 ГБ). Я протестировал обе функции, и там нет никакого цикла бесконечности. Код запускается , когда я ставлю lenarr = 10000 , но я должен протестировать len = 100000 и lenarr равен 200 тысячам, 400 тысячам, 600 тысячам, 800 тысячам и 1 миллиону, поэтому только 10 тысяч не будут работать для меня. Я делаю что-то не так? Есть ли какой-нибудь способ это исправить? У меня никогда раньше не было проблем с памятью ни в одном коде, поэтому я плохо управляю своей памятью в коде.

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

1. Можете ли вы включить определение getDigits?

2. Ладно, я сделал это. Но, по сути, он получает все цифры числа и помещает их в массив. Это keydigits количество цифр в этом числе.

3. Используйте valgring и проверьте, нет ли утечек памяти. Если у вас нет утечек памяти, то при любом выделении добавьте объем выделенной памяти в счетчик и распечатайте его. Посмотрите, где вы выделяете больше всего средств. Попробуйте отладить его самостоятельно. Многочасовой просмотр кода вам совсем не поможет, и мы также не являемся бесплатным сервисом отладки. Выполняйте тяжелую и скучную работу самостоятельно. Это ваше задание, а не наше

4. Посчитайте, сколько раз вы это сделаете getDigits(...) . Для каждого getDigits(...) найдите свое личное free() . Не можешь его найти? Это твоя утечка памяти.

Ответ №1:

Причина утечки

Я посмотрел это в вальгринде, и похоже, что ты пропустил пять бесплатных звонков. Это самая крупная утечка:

 for(cont1 = 0; cont1 lt; len; cont1  ){  digits = getDigits(arr[cont1], amp;countdigits);  for(cont2 = 0; cont2 lt; keydigits amp;amp; cont2 lt; countdigits; cont2  ){  numqntmatrix[digits[cont2]][cont2]  = 1;  }  // free memory returned by getDigits()  free(digits);  }  

Каждый цикл через этот вызов getDigits() , который выделяет память, которая никогда не освобождается.

Другие источники утечек:

  • int keydigits, *digits = getDigits(value, amp;keydigits);
  • int *concatenate = (int *)(malloc(numofdigits * sizeof(int)));
  • int *randomarr = (int *)(malloc(lenarr * sizeof(int)));
  • int *hash_division = (int *)(malloc(len * sizeof(int)));

Как использовать valgrind

Вот как я провел анализ вальгринда:

Во-первых, я сократил количество циклов, выполняемых программой, со 100 тыс. до 10. Это предотвращает нехватку памяти во время работы valgrind.

Во-вторых, я скомпилировал программу с -ggdb помощью , чтобы включить отладочную информацию. Вот команда, которую я использовал:

 gcc test027.c -Wall -Werror -lm -ggdb -o test027  

В-третьих, я управлял вальгриндом с --leak-check=full :

 valgrind --leak-check=full ./test027   

Это показало мне следы источников утечек памяти. Каждый из них выглядит так:

 ==174419== 1,501,600 bytes in 40,000 blocks are definitely lost in loss record 1 of 1 ==174419== at 0x483C7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==174419== by 0x10925C: getDigits (test027.c:16) ==174419== by 0x10940D: hashUVDigitAnalysis (test027.c:50) ==174419== by 0x109988: main (test027.c:118)  

Первое, что вы видите, — это размер утечки памяти (1 501 600 байт). Сначала вы должны устранить самую большую утечку памяти. Далее вы видите, сколько было выделено средств, которые так и не были освобождены. (40 000 блоков). Далее вы видите номера строк той части программы, которая отвечает за это.

Устраните каждую утечку памяти по одному за раз и повторно запустите valgrind. Как только вы устраните все утечки, valgrind покажет этот вывод:

 ==174500== HEAP SUMMARY: ==174500== in use at exit: 0 bytes in 0 blocks ==174500== total heap usage: 43,003 allocs, 43,003 frees, 1,621,428 bytes allocated ==174500==  ==174500== All heap blocks were freed -- no leaks are possible  

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

1. Спасибо тебе, правда. Я не знал Вальгрида до того, как задал этот вопрос, и я устанавливал его и проверял себя, когда вы ответили. Я думал, что, когда я использовал free (digits) в конце функции, это было бы нормально (немного идиотски, я знаю). Я освобожу все getDigits и проверю код позже. Еще раз спасибо вам.