#c #malloc #free
#c #malloc #Бесплатно
Вопрос:
Я пишу программу, которая проверяет динамическое распределение памяти, чтобы увидеть, насколько хорошо выполняется правило 50 процентов.
Программа содержит 10000 указателей на динамически выделяемые блоки памяти. В нем также есть массив для хранения размера каждого блока. Это должно:
- Используется
malloc()
для динамического выделения блока памяти для каждого элементаptrList
. Эти блоки должны иметь размеры, которые выбираются случайным образом в диапазоне от 1 до 10000 байт, и размер блока должен храниться вsizeList
массиве. - После первоначального выделения блоков программа должна повторно освобождать блоки и выделять новые. Цикл должен составлять 100 000 итераций. На каждой итерации индекс в
ptrList
выбирается случайным образом, блок освобождается, а затем заменяется новым динамически выделяемым блоком случайного размера. - После каждых 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?