Постоянно снижающаяся производительность выделения памяти. Пример кода

Не могли бы вы помочь выяснить, в чем причина постоянного снижения производительности кода ниже. Если вы запустите код, вы увидите, что он печатает количество итераций в секунду. Через 10-15 секунд количество итераций в секунду в 2 раза меньше, чем в начале. Сначала проблема возникла в QT, но я переделал код, чтобы проверить его с помощью std, и проблема воспроизводится.

#include <iostream>
#include <vector>
#include <memory>
#include <string>

#include <chrono>


using namespace std;

int64_t GetUsecTime()
{
    return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();
}

namespace IType {
    enum T {
        oI = 0,
        oI_2 = 1,
    };
}

class BaseClass
{
public:
    BaseClass(IType::T t)
        : m_type(t)
    {}

    virtual ~BaseClass() {}

    IType::T type()
    {
        return m_type;
    }

private:
    IType::T m_type;
};

class InheritedClass : public BaseClass
{
public:
    static shared_ptr<InheritedClass> CreateShared(const string& some)
    {
        //return shared_ptr<InheritedClass>(new InheritedClass(some));
        return make_shared<InheritedClass>(some);
    }

    static shared_ptr<InheritedClass> CreateShared()
    {
        //return shared_ptr<InheritedClass>(new InheritedClass(some));
        return make_shared<InheritedClass>();
    }

    InheritedClass(const string& some)
        : BaseClass(IType::oI)
        , someFiled(some)
    {}

    InheritedClass()
        : BaseClass(IType::oI)
        , someFiled("")
    {}

    void setField(const string& value)
    {
        someFiled = value;
    }
private:
    string someFiled;
};


class InheritedClass_2 : public BaseClass
{
public:
    static shared_ptr<InheritedClass_2> CreateShared()
    {
        //return shared_ptr<InheritedClass_2>(new InheritedClass_2());
        return make_shared<InheritedClass_2>();
    }

    InheritedClass_2()
        : BaseClass(IType::oI_2)
    {}

    void setField(int value)
    {
        someFiled = value;
    }
private:
    int someFiled;
};

class someclass
{
public:
    someclass()
    {
        int64_t dataSize(0);
        int64_t oldDataSize(0);
        int64_t time0(GetUsecTime());
        int64_t time(time0);

        for (int i = 0; i<8000000; i++)
        {
            // TEST CONSTRUCTORS
            //auto instance=InheritedClass::CreateShared(); // No Problem...
            auto instance = InheritedClass::CreateShared(""); // PROBLEM!! With this line, speed is constantly decreasing

                                                              //TEST CODE:
                                                              //instance->setField("just something"); // PROBLEM!! With this line, speed is constantly decreasing

            V.push_back(instance);

            auto instance_2 = InheritedClass_2::CreateShared();
            instance_2->setField(i);
            V.push_back(instance_2);

            dataSize = i;

            if (GetUsecTime() - time > 1000000)
            {
                time = GetUsecTime();

                cout << "Processed: " << dataSize - oldDataSize << endl;

                oldDataSize = dataSize;
            }
        }

        cout << V.size() << " in " << (GetUsecTime() - time0) / 1000.0 << " ms" << endl;
    }
private:
    vector<shared_ptr<BaseClass> > V;
};

int main(int argc, char *argv[])
{
    someclass s;

    return 0;
}

код работал в QT и Visual Studio. Распечатка из программы QT ниже (уменьшение с 220000 до 67000):

Processed: 31681
Processed: 196038
Processed: 234112
Processed: 229468
Processed: 216378
Processed: 227070
Processed: 198330
Processed: 211321
Processed: 197137
Processed: 151333
Processed: 167995
Processed: 168307
Processed: 163719
Processed: 153696
Processed: 110894
Processed: 143917
Processed: 137006
Processed: 129974
Processed: 127678
Processed: 124093
Processed: 124029
Processed: 123018
Processed: 118595
Processed: 116676
Processed: 115023
Processed: 73030
Processed: 111768
Processed: 110222
Processed: 103588
Processed: 106266
Processed: 105271
Processed: 105031
Processed: 102042
Processed: 100258
Processed: 99404
Processed: 98955
Processed: 97007
Processed: 95901
Processed: 93696
Processed: 91405
Processed: 91061
Processed: 90175
Processed: 87727
Processed: 87448
Processed: 85510
Processed: 84238
Processed: 41837
Processed: 76040
Processed: 75694
Processed: 82918
Processed: 81515
Processed: 80957
Processed: 79657
Processed: 80840
Processed: 79110
Processed: 78720
Processed: 76078
Processed: 76067
Processed: 75412
Processed: 75546
Processed: 74052
Processed: 73386
Processed: 69608
Processed: 66880
Processed: 68731
Processed: 70560
Processed: 68979
Processed: 69985
Processed: 70516
Processed: 68464
Processed: 67379
Processed: 67980
Processed: 67746
Processed: 67332
16000000 in 74537 ms

Распечатка из программы VisualSutio ниже (начальные значения меньше, менее стабильны, но не уменьшаются):

Processed: 81138
Processed: 78107
Processed: 81158
Processed: 101733
Processed: 69418
Processed: 99900
Processed: 54649
Processed: 94161
Processed: 95660
Processed: 31477
Processed: 97066
Processed: 97588
Processed: 99001
Processed: 99554
Processed: 492
Processed: 99197
Processed: 100049
Processed: 99765
Processed: 100066
Processed: 97667
Processed: 93807
Processed: 100146
Processed: 99378
Processed: 99824
Processed: 98228
Processed: 97943
Processed: 99552
Processed: 100299
Processed: 99753
Processed: 90703
Processed: 98276
Processed: 99480
Processed: 99569
Processed: 99528
Processed: 99058
Processed: 98939
Processed: 97637
Processed: 99334
Processed: 99713
Processed: 99540
Processed: 99212
Processed: 99339
Processed: 98781
Processed: 40334
Processed: 98810
Processed: 99134
Processed: 99953
Processed: 99884
Processed: 99891
Processed: 100036
Processed: 100037
Processed: 98182
Processed: 98393
Processed: 99091
Processed: 98359
Processed: 99515
Processed: 100710
Processed: 99065
Processed: 100507
Processed: 99915
Processed: 96591
Processed: 97256
Processed: 100400
Processed: 99551
Processed: 7829
Processed: 100520
Processed: 99480
Processed: 100201
Processed: 99145
Processed: 100898
Processed: 100403
Processed: 99873
Processed: 99761
Processed: 99590
Processed: 99795
Processed: 100142
Processed: 99396
Processed: 99607
Processed: 98091
Processed: 97379
Processed: 98045
Processed: 98448
Processed: 97853
Processed: 98633
Processed: 96140
16000000 in 96518.3 ms

Если вы пометите язык (я полагаю, C++), вы можете привлечь больше пользователей, которые будут полезны и разбираются в теме.

Yunnosch 21.12.2020 13:21

Вы делаете довольно много ненужных копий с помощью make_shared . make_shared<InheritedClass>(some) и make_shared<InheritedClass_2>() достаточно. (make_shared не берет объект и делает его общим, он делает общий объект.)

molbdnilo 21.12.2020 13:36

Я играл с make_shared и просто с shared_ptr(), на саму упомянутую проблему это никак не повлияло. Тем не менее, спасибо за подсказку.

Dmitry Gorelov 21.12.2020 13:37

Вот мое предположение: someField всегда будет построен по умолчанию. Я думаю, что компилятор может убрать someFiled("") инициализацию во втором конструкторе. Но, вероятно, у него проблемы с удалением пустой строки из строки ::CreateShared(""). И пустые строки не бесплатны, нет. Хотя это зависит от реализации, вполне вероятно, что под капотом для него выделена ненулевая память (емкость). Итак, ::CreateShared("") в два раза тяжелее ::CreateShared().

freakish 21.12.2020 15:02

Это также кажется зависимым от компилятора, см. это: godbolt.org/z/GPod3z Clang генерирует очень плохой код для проверки2. Но Gcc выдает один и тот же код для обоих.

freakish 21.12.2020 15:09

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

Dmitry Gorelov 21.12.2020 15:14

Я запускал код в QT и VisualStudio. Как ни странно, программа в VS работает медленнее (выходные распечатки меньше), но они не уменьшаются! На QT, как ни странно, значения более стабильны, они начинаются с большего значения, но постоянно уменьшаются. Похоже, что зависимость от уже выделенной памяти, а во-вторых, имеет какое-то отношение к внутреннему полю String в instance1. Код довольно простой, но моих знаний недостаточно, чтобы объяснить все эти хитрые вещи.

Dmitry Gorelov 21.12.2020 15:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

Я пробовал list и deque, без изменений. Но я обновил сообщение темы, и Visual Studio дает другой результат (без постоянного снижения) с тем же кодом. Так что вектор, наверное, не причина, если не повод для компилятора VisualStudio? Кстати, вектор НЕ является причиной, потому что можно только закомментировать строки с пометкой //ПРОБЛЕМА, и все будет работать нормально, не тормозя.

Dmitry Gorelov 21.12.2020 15:41

Может быть. Чтобы узнать точно, рассмотрите возможность использования профилировщика. Это сэкономит ваше время.

4xy 21.12.2020 15:43

@Dmitry Gorelov Комментирование и раскомментирование строк кода может иметь побочные эффекты и вызывать проблемы. Я не настаиваю на том, что это имеет место в вашем случае, но единственный способ узнать и решить это — профилировать код.

4xy 21.12.2020 15:49

Спасибо 4xy, ищу профайлера. Тем не менее, я просто надеюсь, что код не так уж и сложен, и кто-то, кто сталкивался с подобными проблемами, мог бы дать ответ. Так что пусть вопрос останется нерешенным на пару дней.

Dmitry Gorelov 21.12.2020 16:03
Ответ принят как подходящий
  1. программа во время теста работала в отладчике QT.
  2. Когда сделал релиз, и запускал его из винды просто как EXE, он работал в 20 раз быстрее! и без тех, кто тормозит.

Итак, решение:

  • Не верьте, когда запускаете свой код в отладчике QT - он в несколько раз медленнее, чем реальное приложение!
  • Не измеряйте время/не оценивайте производительность с помощью отладчика QT.

Новая распечатка из realeas exe:

Processed: 1923592
Processed: 2062627
Processed: 1993109
Processed: 2541079
Processed: 1666522
Processed: 2562799
Processed: 1186022
Processed: 2578212
Processed: 2590275
40000000 in 9599 ms

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