Быстрее / надежнее выделить несколько маленьких блоков вместо одного большого - PullRequest
2 голосов
/ 28 января 2012

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

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

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

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

Ответы [ 5 ]

4 голосов
/ 28 января 2012

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

3 голосов
/ 28 января 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
3 голосов
/ 28 января 2012

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

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

1 голос
/ 28 января 2012

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

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

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

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

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

1 голос
/ 28 января 2012

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

...