2015-03-26 4 views
3

Просто интересно. Ниже приведены два фрагмента кода для одной и той же функции:Когда локальная переменная внутри функции * фактически * распределяется

void MyFunc1() 
{ 
    int i = 10; 
    object obj = null; 

    if(something) return; 
} 

И другая является ...

void MyFunc1() 
{ 
    if(something) return; 

    int i = 10; 
    object obj = null; 
} 

Теперь делает второй один имеет преимущество НЕ распределения переменных, когда что-то является правда? ИЛИ локальные переменные стека (в текущей области) всегда выделяются, как только вызывается функция, и перемещение оператора возврата в начало не влияет?

A link to dotnetperls.com article говорит «При вызове метода в программе C#, среда выполнения выделяет отдельную область памяти для хранения всех локальных переменных слотов. Эта память выделяется в стеке, даже если у вас нет доступа к переменным в вызов функции ".

ОБНОВЛЕНО
Вот сравнение кода IL для этих двух функций. Func2 ссылается на второй отрезанный. Кажется, что переменная в обоих случаях распределяется в начале, хотя в случае Func2() они инициализируются позже. Так что никакой пользы как таковой я не догадываюсь.

ILCode in ILDisassembler

+1

Как насчет просмотра сгенерированного кода [IL code] (http://en.wikipedia.org/wiki/Common_Intermediate_Language)? –

+2

IL имеет мало общего с этим; IL не работает. Код * jitted * - это то, что работает. –

+1

Число высказываний, которые являются неопределенными или вводящими в заблуждение в этой статье, довольно велико. –

ответ

10

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

Любые выделения в стеке локальной переменной строго «детализация реализации». И CLS не обещает нам какой-либо конкретной реализации.

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

Смотрите также отличная серия Эрика Липперта The Stack Is An Implementation Detail

22

ответ Питера Duniho является правильным. Я хочу обратить внимание на более фундаментальную проблему в вашем вопросе:

У второго есть преимущество НЕ выделять переменные, если верно something?

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

Для решения вашего конкретного вопроса:

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

Я не могу легко ответить на такой сложный вопрос. Перейдем к гораздо более простым вопросам:

Переменные - это места хранения. Каковы сроки хранения мест хранения, связанных с локальными переменными?

Место хранения «обычных» локальных переменных - и формальные параметры лямбда, методы и т. Д. - имеют короткие, предсказуемые сроки жизни. Ни один из них не живет до метод вводится, и ни один из них не живет после, метод прекращается, как обычно, так и исключительно. Спецификация языка C# четко указывает на то, что время жизни локальной переменной разрешено во время выполнения короче, чем вы думаете, если это не вызывает заметного изменения однопоточной программы.

Место хранения «необычных» локальных переменных - внешние переменные lambdas, локальные переменные в блоках итератора, локальные переменные в асинхронных методах и т. Д. - имеют времена жизни, которые трудно анализировать во время компиляции или во время выполнения , и поэтому перемещаются в кучу мусора, которая использует политику GC для определения времен жизни переменных. Не требуется, чтобы такие переменные были очищены до; их срок хранения может быть увеличен произвольно по прихоти компилятора C# или времени выполнения.

Может ли локальная система, которая не используется, полностью оптимизирована?

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

Как распределяются места хранения «обычных» местных жителей?

Это деталь реализации, но обычно есть две техники. Любое пространство зарезервировано в стеке, или локально зарегистрировано.

Как среда выполнения определяет, зарегистрирована ли локальная сеть или помещена в стек?

Это деталь реализации оптимизатора джиттера.Существует множество факторов, таких как:

  • может ли быть адресован местный адрес; регистры не имеют адреса
  • передаются ли локальный в качестве параметра другого метода
  • ли локальный является параметром текущего метода
  • то, что соглашения о вызове являются всеми методы участвуют
  • размера местные
  • и многие, многие другие факторы

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

Опять же, это деталь реализации, но, как правило, ответ да.

Таким образом, «стековый локальный», который используется условно, не будет выделен из стека условно? Скорее, его местоположение стека всегда будет выделено.

Как правило, да.

Каковы компромиссы с производительностью, присущие этому решению?

Предположим, у нас есть два локальных объекта: A и B, а один используется условно, а другой используется безоговорочно. Что быстрее:

  • Добавьте две единицы к текущему указателю стека
  • Инициализировать два новых слота стека к нулю

или

  • Добавьте одну единицу к текущему указателю стека
  • Инициализируйте новый слот стека до нуля
  • Если условия on, добавьте один элемент в текущий указатель стека и инициализируйте новый слот стека до нуля.

Имейте в виду, что «добавить один» и «добавить два» имеют одинаковую стоимость.

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

А как насчет космоса? Условная схема использует один или два блока пространства стека, но безусловная схема использует два независимо.

Исправить. Стековое пространство дешево.Или, точнее, миллион байт пространства стека, которое вы получаете за поток, составляет безумно дорого, и этот расход оплачивается перед, когда вы выделяете нить. Большинство программ никогда не используют нигде около миллиона байт пространства стека; попытка оптимизировать использование этого пространства - это как потратить час, решив заплатить 5,01 доллара за латте против 5,02 доллара США, когда у вас есть миллион долларов в банке; это не стоит.

Предположим, что 100% местных жителей на основе стека выделяются условно. Может ли дрожание добавить дополнение к указателю стека после условного кода?

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

И, конечно, насколько реалистично, что миллиардная секунда, которую вы экономите, будет общим путем? Большинство методов звонков что-то делают, а не немедленно возвращаются.

Кроме того, имейте в виду, что указатель стека будет иметь для перемещения всех слотов временных значений, которые не enregistered, независимо от того, являются ли эти слоты имеют имена или нет. Сколько сценариев существует там, где условие, которое определяет, возвращает ли метод сам , не имеет подвыражения, которое касается стека? Потому что это условие, которое вы на самом деле предлагаете оптимизировать. Это похоже на исчезающе небольшой набор сценариев, в которых вы получаете исчезающе малое преимущество. Если бы я писал оптимизатор, я бы потратил ровно нулевой процент моего драгоценного времени на решение этой проблемы, когда есть более сочные сценарии с низким уровнем висячих фруктов, которые я мог бы оптимизировать.

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

Да. В простой схеме, в которой вы перемещаете указатель стека на два слота и говорите, что «указатель стека равен A, указатель стека + 1 есть B», теперь у вас есть метод согласованного по всему методу охарактеризовать переменные A и B. Если вы условно переместите указатель стека, а иногда указатель стека A, иногда это B, а иногда и нет. Это значительно усложняет весь код, который использует A и B.

Что делать, если местные жители enregistered?

Тогда это станет проблемой при составлении реестра; Я отсылаю вас к обширной литературе по этому вопросу. Я далек от эксперта.

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