С++ производительность глобальных переменных

Для пояснения: я знаю, как злые глобальные существа и когда не использовать их:)

  • Есть ли ограничение производительности при доступе/установке глобальной переменной по сравнению с локальной в скомпилированной программе на С++?

Ответ 1

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

Ответ 2

Это зависит, но обычно да, хотя это микро-проблема. Глобальные переменные должны быть ссылочными из многих контекстов, а это значит, что включение их в регистр невозможно. В то время как в случае локальных переменных это возможно и предпочтительнее. Фактически, чем более узкая область применения, тем больше у компилятора есть возможность оптимизировать доступ/изменение этой переменной.

Ответ 3

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

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

Локальные переменные привязаны к функции, поэтому компилятор может предположить, что они не будут изменены никакими другими вызовами функций. С глобальным компилятором может быть принудительно перезагрузить глобальное значение.

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

Ответ 4

Строго говоря, нет.

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

Ответ 5

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

Ответ 6

Ответ привязан к общей структуре программы.

Например, я просто разобрал это, и в обоих случаях переменная цикла была перемещена в регистр, после чего не было никакой разницы:

int n = 9;
int main()
{
    for (n = 0; n < 10; ++n)
        printf("%d", n);

    for (int r = 0; r < 10; ++r)
        printf("%d", r);

    return 0;
}

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

Ответ 7

В любом случае нет штрафа за производительность, о котором вы должны беспокоиться. Принимая во внимание то, что говорили все остальные, вы также должны учитывать пейджинговые накладные расходы. Локальные переменные экземпляра извлекаются из структуры объекта, которая, скорее всего, (?) Уже была выгружена в кэш-память). С другой стороны, глобальные переменные могут вызывать различную структуру подкачки виртуальной памяти.

Опять же, производительность на самом деле не стоит рассматривать с вашей стороны.

Ответ 8

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

Ответ 9

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

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

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