Вопрос

Я работаю над системой обработки событий в мягкой реальности. Я хотел бы свести к минимуму столько вызовов в моем коде, которые имеют не определенное время. Мне нужно построить сообщение, которое состоит из строк, чисел, временных метров и GUID. Вероятно, а std::vector из boost::variantS.

Я всегда хотел использовать alloca в прошлом кодексе аналогичного характера. Однако, когда кто -то изучает литературу по программированию систем, всегда есть огромные предостережения против этого вызова функции. Лично я не могу вспомнить машину класса сервера за последние 15 лет, у которой нет виртуальной памяти, и я точно знаю, что стек Windows выращивает страницу виртуальной памяти в время, поэтому я предполагаю Unices делают тоже. Здесь нет кирпичной стены (больше), стек с такой же вероятностью не хватит места, как и куча, так что дает? Почему люди не ходят по Алоке? Я могу вспомнить о многих вариантах использования ответственного использования Alloca (обрабатывает кого-нибудь строки?).

В любом случае, я решил проверить разницу в производительности (см. Ниже), и между Alloca и Malloc существует 5-кратная разница в скорости (тест охватывает, как я буду использовать Alloca). Итак, все изменилось? Должны ли мы просто поддерживать осторожность и использовать alloca (завернут в std::allocator) всякий раз, когда мы можем быть абсолютно уверены в жизни наших объектов?

Я устал жить в страхе!

Редактировать:

Итак, есть пределы, для Windows это ограничение на ссылку. Для Unix это кажется настраиваемым. Похоже, что распределитель памяти, выдвинутые на страницу, в порядке: D Кто-нибудь знает о портативной реализации общего назначения: D?

Код:

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

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

using namespace boost::posix_time;

int random_string_size()
{
    return ( (rand() % 1023) +1 );
}

int random_vector_size()
{
    return ( (rand() % 31) +1);
}

void alloca_test()
{
    int vec_sz = random_vector_size();

    void ** vec = (void **) alloca(vec_sz * sizeof(void *));    

    for(int i = 0 ; i < vec_sz ; i++)
    {
        vec[i] = alloca(random_string_size());     
    }
}

void malloc_test()
{
    int vec_sz = random_vector_size();

    void ** vec = (void **) malloc(vec_sz * sizeof(void *));    

    for(int i = 0 ; i < vec_sz ; i++)
    {
        vec[i] = malloc(random_string_size());     
    }

    for(int i = 0 ; i < vec_sz ; i++)
    {
        free(vec[i]); 
    }

    free(vec);
}

int main()
{
    srand( time(NULL) );
    ptime now;
    ptime after; 

    int test_repeat = 100; 
    int times = 100000;


    time_duration alloc_total;
    for(int ii=0; ii < test_repeat; ++ii)
    { 

        now = microsec_clock::local_time();
        for(int i =0 ; i < times ; ++i)
        {
            alloca_test();    
        }
        after = microsec_clock::local_time();

        alloc_total += after -now;
    }

    std::cout << "alloca_time: " << alloc_total/test_repeat << std::endl;

    time_duration malloc_total;
    for(int ii=0; ii < test_repeat; ++ii)
    {
        now = microsec_clock::local_time();
        for(int i =0 ; i < times ; ++i)
        {
            malloc_test();
        }
        after = microsec_clock::local_time();
        malloc_total += after-now;
    }

    std::cout << "malloc_time: " << malloc_total/test_repeat << std::endl;
}

выход:

hassan@hassan-desktop:~/test$ ./a.out 
alloca_time: 00:00:00.056302
malloc_time: 00:00:00.260059
hassan@hassan-desktop:~/test$ ./a.out 
alloca_time: 00:00:00.056229
malloc_time: 00:00:00.256374
hassan@hassan-desktop:~/test$ ./a.out 
alloca_time: 00:00:00.056119
malloc_time: 00:00:00.265731

-Редакция: Результаты на домашней машине, кланге и Google Perftools--

G++ without any optimization flags
alloca_time: 00:00:00.025785
malloc_time: 00:00:00.106345


G++ -O3
alloca_time: 00:00:00.021838
cmalloc_time: 00:00:00.111039


Clang no flags
alloca_time: 00:00:00.025503
malloc_time: 00:00:00.104551

Clang -O3 (alloca become magically faster)
alloca_time: 00:00:00.013028
malloc_time: 00:00:00.101729

g++ -O3 perftools
alloca_time: 00:00:00.021137
malloc_time: 00:00:00.043913

clang++ -O3 perftools (The sweet spot)
alloca_time: 00:00:00.013969
malloc_time: 00:00:00.044468
Это было полезно?

Решение

Ну, во -первых, даже если много виртуальной памяти не означает, что ваш процесс будет разрешен его заполнить. На *nix существуют ограничения размера стека, тогда как куча намного более прощающая.

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

Почему использование Alloca () не считается хорошей практикой?

На моем ящике для разработки на работе (Gentoo) у меня есть предел размера стека по умолчанию 8192 КБ. Это не очень большое, и если Alloca переполняет стек, то поведение не определен.

Другие советы

Я думаю, что вам нужно быть немного осторожным, понимая, что такое Alloca. В отличие от Malloc, которая идет на кучу, поиск по ведрах и связанных спискам различных буферов, Alloca просто принимает ваш регистр стека (ESP на x86) и перемещает его, чтобы создать «отверстие» в стеке вашей потока, где вы можете хранить все, что хотите. Вот почему это безумно, только одна (или мало) инструкции по сбору.

Таким образом, как отмечали другие, это не «виртуальная память», о которой вам нужно беспокоиться, а размер, зарезервированный для стека. Хотя другие ограничиваются «несколькими сотнями байтов», если вы знаете свое приложение и осторожно о нем, мы выделили до 256 КБ без каких -либо проблем (размер стека по умолчанию, по крайней мере для визуальной студии, составляет 1 МБ, и вы всегда можете Увеличьте его, если вам нужно).

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

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

Во -первых, это потому, что alloca Память очень сложно контролировать. Он нетипирован, умирает при первой же возможности, что делает его не очень полезным. Кроме того, alloca Имеет некоторые неудачные побочные эффекты, и эти побочные эффекты заключаются в том, что регулярные переменные стека теперь должны быть динамически индексировать вместо константов, что может повлиять на вашу производительность даже в базовых операциях, доступа к ним, и потребляет пространство для регистрации/стека для хранения динамических смещений. Это означает, что реальная стоимость использования alloca не записано только в то время, которое требуется для возврата функции. Кроме того, память стека очень ограничена по сравнению с памятью кучи. В Windows ограничение стека по умолчанию составляет 8 МБ, я по умолчанию, тогда как куча может быть почти все адресное пространство пользователя. Более того, в конечном счете, какие данные, которые вы хотите вернуть, должны быть на куче, так что вы можете просто использовать это в качестве рабочего пространства.

Один пункт, который не был сделан AFAI, это то, что стек часто смежный, в то время как куча нет. В целом не правда сказать, что стек так же вероятно, что заканчивается память, как куча.

В C ++ очень часто рассматривать экземпляры объектов как местные жители, что вроде как alloca Но из структурированной памяти, а не блока n байтов - возможно, вы можете думать об этом как о своем главном вопросе, что является хорошей идеей более широкого использования памяти на основе стека. Я бы раньше сделал это (объявить экземпляр объекта как локальный raii), чем использовать malloc (или же alloca) в программе C ++. Всех тех, кто free Звонки, чтобы сделать исключение-безопасным ...

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

Стек Windows не растет - его зарезервированный размер устанавливается во время ссылки, но страницы в пределах этого размера будут совершены только по мере необходимости. Видеть http://msdn.microsoft.com/en-us/library/ms686774%28v=vs.85%29.asp. Анкет Поскольку зарезервированный размер по умолчанию составляет 1 МБ, вы можете легко превзойти это при использовании alloca().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top