Realloc vs (malloc + memset) - C (СИ)
Формулировка задачи:
На одном форуме мне сказали, что realloc работает чуть ли не в полтора раза медленнее связки malloc + memset. Вот решил проверить (и ужаснуться, как выяснилось позже). Программы простые, единственный параметр командной строки задает начальный размер массива. Может, конечно, я где в коде накосячил, так что гляньте свежим взглядом заодно.
Вот код:
malloc + memcpy
realloc
результаты такие (у меня FreeBSD 9.1, amd64):
Если в коде косяков нет, то почему такая большая разница в производительности?
Кому не лень, для статистики, просьба запустить тесты у себя и выложить результат (с указанием ОС).
теперь realloc отдает разные адреса, но, даже с учетом вывода в файл, работает в неизвестно сколько раз быстрее (malloc падает при начальном размере в 36 int'ов, realloc при таких условиях отрабатывает за время 0,00 real 0,00 user 0,00 sys) Так что мой вопрос остается открытым!
#include <stdio.h> #include <stdlib.h> #include <string.h> unsigned long int size; int main(int argc, char* argv[]) { int *buffer, *buffer2; int crc = 0; unsigned long int i, j; if(argc != 2) return 1; size = atol(argv[1]); buffer = (int*)malloc(size * sizeof(int)); if(buffer == 0) { puts("ERR1"); exit(1); } i = 0; while(i < size) { crc += buffer[i]; ++i; } for(j = 0; j < 10000; ++j) { buffer2 = (int*)malloc((j + size) * sizeof(int)); if(buffer2 == 0) { puts("ERR2"); exit(1); } memcpy(buffer2, buffer, (j + size - 1) * sizeof(int)); buffer = buffer2; } i = 0; while(i < size + j - 1) { crc += buffer[i]; ++i; } printf("%d %li\n", crc, size); return 0; }
#include <stdio.h> #include <stdlib.h> unsigned long int size; int main(int argc, char* argv[]) { int *buffer; int crc = 0; unsigned long int i, j; if(argc != 2) return 1; size = atol(argv[1]); buffer = (int*)malloc(size * sizeof(int)); if(buffer == 0) { puts("ERR1"); exit(1); } i = 0; while(i < size) { crc += buffer[i]; ++i; } for(j = 0; j < 10000; ++j){ buffer = (int*)realloc(buffer, (j + size) * sizeof(int)); if(buffer == 0) { puts("ERR2"); exit(1); } } i = 0; while(i < size + j - 1) { crc += buffer[i]; ++i; } printf("%d %li\n", crc, size); return 0; }
$ gcc49 -Wall malloc_test.c -o malloc $ gcc49 -Wall realloc_test.c -o realloc $ time ./realloc 100000000 0 100000000 0,56 real 0,44 user 0,11 sys $ time ./malloc 100000000 time: command terminated abnormally 3,05 real 1,18 user 1,60 sys Killed $ time ./realloc 10000 0 10000 0,01 real 0,00 user 0,00 sys $ time ./malloc 10000 0 10000 1,36 real 0,57 user 0,78 sys $ gcc49 -Wall -O4 malloc_test.c -o malloc $ gcc49 -Wall -O4 realloc_test.c -o realloc $ time ./realloc 100000000 0 100000000 0,42 real 0,14 user 0,27 sys $ time ./malloc 100000000 time: command terminated abnormally 3,13 real 0,87 user 1,99 sys Killed $ time ./realloc 100000 0 100000 0,00 real 0,00 user 0,00 sys $ time ./malloc 100000 0 100000 1,28 real 0,40 user 0,87 sys
realloc не заморачивался и отдавал память по старому адресу, чтобы ничего не копировать.
заменил рост буфера (вместо прибавления размера на один int сделал домножение размера)
for(j = 1; j < 10000; ++j){ buffer = (int*)realloc(buffer, (j * size) * sizeof(int)); printf("%p\n", buffer); if(buffer == 0) { puts("ERR2"); exit(1); } }
для тестов, полная версия с домножением размера буфера
#include <stdio.h> #include <stdlib.h> #include <string.h> unsigned long int size; int main(int argc, char* argv[]) { int *buffer, *buffer2; int crc = 0; unsigned long int i, j; if(argc != 2) return 1; size = atol(argv[1]); buffer = (int*)malloc(size * sizeof(int)); if(buffer == 0) { puts("ERR1"); exit(1); } i = 0; while(i < size) { crc += buffer[i]; ++i; } for(j = 1; j < 10000; ++j) { buffer2 = (int*)malloc((j * size) * sizeof(int)); if(buffer2 == 0) { puts("ERR2"); exit(1); } memcpy(buffer2, buffer, (size * (j - 1)) * sizeof(int)); buffer = buffer2; } i = 0; while(i < size * j - 1) { crc += buffer[i]; ++i; } printf("%d %li\n", crc, size); return 0; }
#include <stdio.h> #include <stdlib.h> unsigned long int size; int main(int argc, char* argv[]) { int *buffer; int crc = 0; unsigned long int i, j; if(argc != 2) return 1; size = atol(argv[1]); buffer = (int*)malloc(size * sizeof(int)); if(buffer == 0) { puts("ERR1"); exit(1); } i = 0; while(i < size) { crc += buffer[i]; ++i; } for(j = 1; j < 10000; ++j){ buffer = (int*)realloc(buffer, (j * size) * sizeof(int)); if(buffer == 0) { puts("ERR2"); exit(1); } } i = 0; while(i < size * j - 1) { crc += buffer[i]; ++i; } printf("%d %li\n", crc, size); return 0; }
Решение задачи: «Realloc vs (malloc + memset)»
textual
Листинг программы
for(j = 1; j < 10000; ++j){ buffer = (int*)realloc(buffer, (j * size) * sizeof(int)); if(buffer2 == buffer) ++h; buffer2 = buffer; if(buffer == 0) { puts("ERR2"); exit(1); } }
Объяснение кода листинга программы
В этом коде выполняется следующее:
- Выделяется память под массив int с помощью функции realloc.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Выполняется проверка выделенной памяти на равенство нулю.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Выполняется цикл, который повторяется 10000 раз.
- В каждой итерации цикла выполняется следующее:
- Выделяется память под массив int с помощью функции realloc.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Выполняется проверка выделенной памяти на равенство нулю.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Размер массива увеличивается на 1.
- Если размер массива равен 10000, то выполняется попытка выделить память под массив int с помощью функции realloc.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Выполняется проверка выделенной памяти на равенство нулю.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Размер массива увеличивается на 1.
- Если размер массива равен 10000, то выполняется попытка выделить память под массив int с помощью функции realloc.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
- Выполняется проверка выделенной памяти на равенство нулю.
- Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д