Realloc vs (malloc + memset) - C (СИ)

Узнай цену своей работы

Формулировка задачи:

На одном форуме мне сказали, что realloc работает чуть ли не в полтора раза медленнее связки malloc + memset. Вот решил проверить (и ужаснуться, как выяснилось позже). Программы простые, единственный параметр командной строки задает начальный размер массива. Может, конечно, я где в коде накосячил, так что гляньте свежим взглядом заодно. Вот код: malloc + memcpy
#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;
}
realloc
#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;
}
результаты такие (у меня FreeBSD 9.1, amd64):
$ 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);
        }
    }
теперь 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 = 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);
        }
    }

Объяснение кода листинга программы

В этом коде выполняется следующее:

  1. Выделяется память под массив int с помощью функции realloc.
  2. Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
  3. Выполняется проверка выделенной памяти на равенство нулю.
  4. Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
  5. Выполняется цикл, который повторяется 10000 раз.
  6. В каждой итерации цикла выполняется следующее:
    • Выделяется память под массив int с помощью функции realloc.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
    • Выполняется проверка выделенной памяти на равенство нулю.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
    • Размер массива увеличивается на 1.
    • Если размер массива равен 10000, то выполняется попытка выделить память под массив int с помощью функции realloc.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
    • Выполняется проверка выделенной памяти на равенство нулю.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
    • Размер массива увеличивается на 1.
    • Если размер массива равен 10000, то выполняется попытка выделить память под массив int с помощью функции realloc.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.
    • Выполняется проверка выделенной памяти на равенство нулю.
    • Если выделенная память равна нулю, то выводится сообщение об ошибке и программа завершается.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4 из 5
Похожие ответы