То, что вы хотите, может быть достигнуто путем выделения программы меньшими порциями.
Вы должны настроить свой алгоритм так, чтобы он обрабатывал кучу небольших подмассивов, которые затем можно освобождать после использования.
В этом случае может быть полезно распределить блоки в обратном направлении, чтобы дать libc возможность освободить освобожденную память для базовой ОС.
Позвольте мне немного улучшить здесь:
Предположим, вы хотите массив с 10000000 (10 миллионов) записей. Вместо того, чтобы выделять его как один кусок, как показано в вопросе, можно иметь
#define CHUNKSIZE 10000
#define ENTRYSIZE 8
#define NUM_CHUNKS 1000
void test(void)
{
void** outer_array = malloc(NUM_CHUNKS * sizeof(void*))
for (int i = 0; i < NUM_CHUNKS; i++) {
void * chunk = malloc(CHUNKSIZE * ENTRYSIZE);
outer_array[NUM_CHUNKS - 1 - i] = chunk;
// allocate them in reverse order
}
// now, set item #123456
size_t item_index = 123456;
// TODO check if the index is below the maximum
size_t chunk_index = item_index / CHUNKSIZE;
size_t index_into_chunk = item_index % CHUNKSIZE;
void * item_address = &outer_array[chunk_index][index_into_chunk * ENTRY_SIZE];
// after having processed one chunk, you can free it:
free(outer_array[0]);
outer_array[0] = NULL;
}
Есть (примерно) две возможности, как программа может увеличить кучу для выделения памяти:
- Он может получить совершенно новый блок памяти от ОС, независимый от «основного адресного пространства». Затем он может использовать его для распределения и вернуть его ОС, как только он станет
free()
d. Это происходит в некоторых распределителях, если размер выделения превышает определенный порог.
- Может улучшить адресное пространство программы. Затем новая память добавляется в конце. После
free()
последнего блока памяти адресное пространство программы может быть снова уменьшено. Это происходит в некоторых распределителях, если размер выделения ниже определенного порога.
Таким образом, объем памяти вашей программы со временем уменьшается.