Любой более быстрый/надежный для выделения нескольких небольших блоков, а не 1 большой блок

У меня есть программа, в которой я выделяю несколько буферов как часть очереди приема для получения сообщений из порта (протокол UDP). В настоящее время буферы не являются смежными, но теперь я рассматриваю возможность сделать их смежными, чтобы при необходимости можно было легко склеить их вместе. Является ли менее надежным/быстрым запросить 1 большой блок памяти, в отличие от многократного выделения меньших блоков.

Общий размер, на который я смотрю, составляет 1000 буферов по 2 КБ, поэтому 2 МБ.

И, пожалуйста, не говорите мне, что я должен использовать TCP; если бы я мог, я бы.

Кстати, я использую c++ и компилирую в VS2005.


person Ian    schedule 27.01.2012    source источник
comment
Трудно придумать способ сделать удаление кода проблемой надежности. Код, который не написан, гарантирует отсутствие ошибок. Опять же, никогда не связывайтесь с кодом, который уже работает.   -  person Hans Passant    schedule 28.01.2012
comment
Вероятно, надежнее получить один большой запрос, если все в порядке, пока они не окажутся в одной точке.   -  person Mooing Duck    schedule 28.01.2012
comment
1000 буферов по 2 КБ = 2048000 байт, 2 МБ = 2097152 байта   -  person LihO    schedule 28.01.2012
comment
Кажется, это похожий вопрос: stackoverflow.com/questions/2984434/small-objects -allocator Я бы использовал проверенное решение, такое как BOOST.   -  person Pablo Diaz    schedule 28.01.2012
comment
@HansPassant Я беспокоился о том, что он будет менее надежным в случае, когда система была ограничена в ОЗУ и не могла найти непрерывный блок длиной 2 МБ, и в этом случае я подумал, что выделение нескольких блоков меньшего размера может быть более надежным. Я говорю не о реальной надежности моего кода, а о надежности его работы.   -  person Ian    schedule 28.01.2012
comment
Нет, выделение 0,1% доступного виртуального адресного пространства — это не проблема, о которой вам следует беспокоиться.   -  person Hans Passant    schedule 28.01.2012


Ответы (5)


Выделение большого блока обычно происходит быстрее, чем выделение нескольких маленьких блоков. Каждое выделение имеет накладные расходы, поэтому при одном большом распределении вы платите накладные расходы один раз, а не много раз.

person carpat    schedule 27.01.2012

Определенно быстрее выделить один большой блок вместо множества меньших блоков. Однако у него есть и свои недостатки. Когда вы выделяете небольшие блоки, очевидно, какому запросу принадлежит какой блок. Когда вы закончите, вы освободите маленький блок.

Если вы выделяете большой блок, вам необходимо реализовать какую-то схему распределения, чтобы зарезервировать диапазоны большого блока для ваших запросов и добавить их обратно в свободный пул после их выполнения. Так что в этой области будут накладные расходы. Если у вас есть дополнительные требования (как вы упомянули, объединение некоторых запросов потребует резервирования непрерывной области для нескольких запросов), вам также придется реализовать эти функции в своем пользовательском распределителе. Таким образом, вы будете добавлять некоторый уровень сложности (и ошибок) в свой код.

person vhallac    schedule 27.01.2012

1000 аллокаций — это не так уж плохо, 1000000 — это число, когда возникают действительно уродливые накладные расходы.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
    int i;
    void* bigPtr;
    void* ptrArray[1000];

    clock_t t1, t2, t3;

    t1 = clock();
    for (i = 0; i < 1000; ++i)
    {
        ptrArray[i] = malloc(2048);
    }
    t2 = clock();

    bigPtr = malloc(i*2048);

    t3 = clock();

    printf("1 big allocation: %.0f ms, %i small allocations = %.0f ms\n",
        difftime(t3, t2), i, difftime(t2, t1));

    return 0;
}

вывод:

1 big allocation: 0 ms, 1000 small allocations = 2 ms
1 big allocation: 0 ms, 10000 small allocations = 9 ms
1 big allocation: 0 ms, 100000 small allocations = 80 ms
1 big allocation: 0 ms, 1000000 small allocations = 733 ms
person LihO    schedule 27.01.2012

Это, безусловно, быстрее, так как потребуется меньше операций выделения/освобождения. Я не могу придумать ни одной причины, по которой это было бы более или менее надежным, если максимальный размер выделения находится в пределах вашего распределителя (который составляет 2 МБ).

person David Schwartz    schedule 27.01.2012

Пользовательские аллокаторы могут работать быстрее, когда у вас много мелких объектов, для больших объектов (массивы мелких объектов должны попадать в это ведро) это менее вероятно. Они не предназначены для размещения большого количества мелких объектов.

Я не уверен, что ожидаю, что буферы uint8_t будут выделяться на порядок быстрее в пользовательском распределителе.

Я бы не сказал, что замена распределителя может быть более надежной. Вы заменяете то, что доказало свою эффективность.

Если у вас есть фиксированный объем памяти, вы можете просто захотеть предварительно выделить все и скопировать значения, когда они выходят из строки. Я бы истолковал это как более простое решение, позволяющее избежать этого узкого места.

Предположим, что это узкое место. Вы профилировали это правильно?

person Tom Kerr    schedule 27.01.2012