#c #arrays #performance #resize #realloc
#c #массивы #Производительность #изменение размера #перераспределить
Вопрос:
У меня есть функция, которая принимает массив строк (буфер) и должна увеличить его размер. Поэтому я вызываю перераспределение
temp = (char**) realloc (buffer, newSize * (sizeof(char*)));
if (temp == NULL)
return false;
else
buffer = temp;
И до сих пор все в порядке. Теперь для каждой новой ячейки я должен вызывать malloc с правильным размером. Обратите внимание, что NewSize всегда четный, а нечетные строки имеют длину, отличную от четных.
for (i = oldSize; i < newSize; i ){
support = (char*) malloc (LENGTH1 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
i ;
support = (char*) malloc (LENGTH2 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
}
Дело в том, что, поскольку я работаю с огромными данными, рано или поздно я закончу память, и перераспределение или один из mallocs завершится неудачей. Проблема в том, что если это один из mallocs, который выходит из строя, существует риск того, что мне придется вызывать миллионы free, чтобы очистить некоторую память. Это занимает много времени. Есть ли какой-нибудь способ ускорить этот процесс или даже лучше избежать его?
if (failedMalloc){
for (i = oldRows; i < marker; i )
free(buffer[i]);
temp = (char**) realloc (buffer, oldRows * (sizeof(char*)));
}
PS: Да, я знаю, что арифметика указателей выполняется быстрее, чем индексация массива.Я реализую его, когда найду способ решить эту проблему, на данный момент я предпочитаю использовать индексацию массива, потому что я нахожу ее менее подверженной ошибкам. Но в окончательной версии будет использоваться арифметика указателей
Комментарии:
1. Арифметика указателей выполняется не быстрее, чем индексация массива
2. @sth, я обнаружил то же самое в своем бенчмаркинге — архитектура x86 имеет встроенную индексацию на уровне инструкций, поэтому, если вы все равно перебираете индекс, вы получаете его бесплатно.
Ответ №1:
Вместо выделения каждой строки по отдельности, выделяйте их блоками. Вы могли бы, например, malloc 128*(LENGTH1 LENGTH2) и иметь место для 256 последовательных строк. Всякий раз, когда ваш индекс пересекает границу блока, выделите другой большой блок и используйте арифметику по модулю, чтобы получить смещение в нем для начала строки.
PS sizeof(char) гарантированно равен 1.
Комментарии:
1. Вариант этого понятия: malloc((NewSize / 2) * (LENGTH1 LENGTH2) (NewSize amp; 1 ? ДЛИНА1 : 0));
2. Просто нужно помнить, что в этом случае не следует освобождать каждую строку по отдельности… просто каждый блок строк, когда ни одна из строк в блоке больше не нужна. Кроме того, если он заполняет адреса отдельных строк в подобном цикле, он мог бы так же легко использовать арифметику указателей, а не арифметику по модулю, чтобы получить их адреса, если он предпочитает.
3. Не могли бы вы дать мне небольшой пример исходного кода? Я не уверен, что понял, что вы предлагаете.. особенно я не понимаю, как получить доступ к этим блокам строк, потому что то, что я пробовал, разбилось. Кроме того, я не знаю, имеет ли это значение, но я не могу использовать malloc(), я должен перераспределить (), потому что я увеличиваю уже существующий массив
4. @Alex Сохраните
realloc
часть… но когда вы выделяете новые строки, выделите достаточно места для 256 (но только тогда, когдаi % 256 == 0
). Затем добавьте соответствующие смещения к этомуmalloc
адресу ed при заполнении вашегоbuffer
массива.
Ответ №2:
Выделяйте большие блоки памяти. Чем меньше вызовов malloc, тем лучше. Самым быстрым будет предварительное вычисление требуемого размера и выделение только один раз.
Кроме того, использование арифметики указателей не приведет к какой-либо видимой разнице здесь.
Ответ №3:
Вы могли бы написать свои собственные процедуры выделения и освобождения и использовать их вместо malloc/free
строк. Если ваши процедуры malloc
обрабатывают один или несколько больших буферов и выделяют из них маленькие кусочки, то вы можете освободить весь массив за один раз, просто вызвав free
каждый большой буфер.
Общая идея работает особенно хорошо в случае, когда все выделения имеют одинаковый размер, и в этом случае она называется «распределителем пула». В этом случае для каждого массива или строк у вас может быть один связанный пул для LENGTH1
выделения, а другой для LENGTH2
.
Я говорю: «напишите свой собственный», но, без сомнения, есть простые распределители пула с открытым исходным кодом, которые можно использовать.
Ответ №4:
Один из способов избежать ненужной памяти — каждый раз использовать больший объем памяти, когда вам нужно malloc,
malloc фиксированный размер (выровнять по 2 ^ n), например
int m_size = 1;
// when need malloc
while (m_size < require_size) m_size * 2;
malloc(m_size);