Si lo uso malloc
, ¿ malloc
usa siempre el mismo algoritmo independientemente de lo que esté asignando o mira los datos y selecciona un algoritmo apropiado?
¿Podemos hacer malloc más rápido o más inteligente eligiendo un algoritmo más eficiente? En mis pruebas, el sistema oficial incorporado malloc
de Ubuntu es 10 veces más lento que un proyecto escolar si los resultados de mi prueba son correctos. ¿Cuál es la trampa? Me sorprende que haya malloc
funcionado tan mal en las pruebas porque debería optimizarse. ¿Utiliza siempre el mismo algoritmo? ¿Hay una implementación de referencia de malloc
? Si quiero ver la fuente malloc
, ¿cuál debo mirar? Las pruebas que ejecuto son las siguientes:
/* returns an array of arrays of char*, all of which NULL */
char ***alloc_matrix(unsigned rows, unsigned columns) {
char ***matrix = malloc(rows * sizeof(char **));
unsigned row = 0;
unsigned column = 0;
if (!matrix) abort();
for (row = 0; row < rows; row++) {
matrix[row] = calloc(columns, sizeof(char *));
if (!matrix[row]) abort();
for (column = 0; column < columns; column++) {
matrix[row][column] = NULL;
}
}
return matrix;
}
/* deallocates an array of arrays of char*, calling free() on each */
void free_matrix(char ***matrix, unsigned rows, unsigned columns) {
unsigned row = 0;
unsigned column = 0;
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
/* printf("column %d row %d\n", column, row);*/
free(matrix[row][column]);
}
free(matrix[row]);
}
free(matrix);
}
int main(int agrc, char **argv) {
int x = 10000;
char *** matrix = alloc_matrix(x, x);
free_matrix(matrix, x, x);
return (0);
}
¿Está bien la prueba? También uso esta prueba:
for (i = 0; i < 1000000; i++) {
void *p = malloc(1024 * 1024 * 1024);
free(p);
}
- actualizar
De acuerdo con el comentario, debería hacer trozos de tamaño variable y libres en un orden diferente al de asignación, así que intento:
int main(int agrc, char **argv) {
int i;
srand(time(NULL));
int randomnumber;
int size = 1024;
void *p[size];
for (i = 0; i < size; i++) {
randomnumber = rand() % 10;
p[i] = malloc(1024 * 1024 * randomnumber);
}
for (i = size-1; i >= 0; i--) {
free(p[i]);
}
int x = 1024;
char *** matrix = alloc_matrix(x, x);
free_matrix(matrix, x, x);
return (0);
}
Entonces mi malloc personalizado ya no es más rápido:
$ time ./gb_quickfit
real 0m0.154s
user 0m0.008s
sys 0m0.144s
dac@dac-Latitude-E7450:~/ClionProjects/omalloc/openmalloc/overhead$ time ./a.out
real 0m0.014s
user 0m0.008s
sys 0m0.004s
El algoritmo que utilicé fue:
void *malloc_quick(size_t nbytes) {
Header *moreroce(unsigned);
int index, i;
index = qindex(nbytes);
/*
* Use another strategy for too large allocations. We want the allocation
* to be quick, so use malloc_first().
*/
if (index >= NRQUICKLISTS) {
return malloc_first(nbytes);
}
/* Initialize the quick fit lists if this is the first run. */
if (first_run) {
for (i = 0; i < NRQUICKLISTS; ++i) {
quick_fit_lists[i] = NULL;
}
first_run = false;
}
/*
* If the quick fit list pointer is NULL, then there are no free memory
* blocks present, so we will have to create some before continuing.
*/
if (quick_fit_lists[index] == NULL) {
Header* new_quick_fit_list = init_quick_fit_list(index);
if (new_quick_fit_list == NULL) {
return NULL;
} else {
quick_fit_lists[index] = new_quick_fit_list;
}
}
/*
* Now that we know there is at least one free quick fit memory block,
* let's use return that and also update the quick fit list pointer so that
* it points to the next in the list.
*/
void* pointer_to_return = (void *)(quick_fit_lists[index] + 1);
quick_fit_lists[index] = quick_fit_lists[index]->s.ptr;
/* printf("Time taken %d seconds %d milliseconds", msec/1000, msec%1000);*/
return pointer_to_return;
}
sbrk
(o lo que sea que usen los asignadores modernos).
calloc
y luego explícitamente claro?
malloc
es más lenta. Eso es lo que esperaría.