2010-05-19 3 views
10

Для уточнения: я знаю, как зло Глобалы и когда их не использовать :)C++ глобальных переменных

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

Лучшим вопросом будет «Почему это важно?» Когда кто-то запускает микро-оптимизирующие детали, подобные этому, он говорит мне, что у них проблемы с производительностью и они ищут способы исправить это. Если это так, * профиль * и найти узкие места. Не потейте такого рода вещи. Это не стоит вашего времени. – greyfade

+0

Во всяком случае, я думаю, что, наконец, я нашел способ повысить репутацию без лишних хлопот: достаточно задать вопрос с «исполнением», брошенным посередине, и вдруг вы получите так много голосов, что не знаете, что делать с ними! –

+0

«Я знаю, как злые глобальные существа и когда их не используют»: никогда не бывает веской причины использовать глобальную переменную, только лень. Единственные глобальные переменные, которые вы должны иметь, - это константы. –

ответ

5

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

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

20

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

+0

Почему так много зависит от моей архитектуры машины :(Это затрудняет оптимизацию. –

+1

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

+4

@ Компьютеры Acula Computers - это машины реального мира, а не идеализированные концепции. Если вам нужен ваш код для запуска как можно быстрее, вы должны учитывать различные причуды реальной машины. Конечно, 99,99% времени, когда вам не нужно, чтобы ваш код работал как можно быстрее, достаточно быстро - в этом случае вы не должны даже подумайте об оптимизации, но оставьте вещи до компилятора. – 2010-05-19 18:24:20

7

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

+1

На самом деле вы можете поместить глобальную переменную в регистр в gcc: register unsigned long * ds asm («ebx»); но это, вероятно, медленнее, так как вы голодали на всю вашу кодовую базу реестра. – geocar

5

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

2

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

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

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; 
} 

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

6

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

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

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

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

1

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

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

1

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

1

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

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

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

Смежные вопросы