2011-01-19 4 views
5

Могут ли оптимизаторы, выполняемые компилятором C# или JITter, иметь видимые побочные эффекты?Оптимизация C# и побочные эффекты

Один пример, который у меня есть.

var x = new Something(); 
A(x); 
B(x); 

При вызове A(x)x гарантированно сохранить жизнь до конца A - потому что B использует один и тот же параметр. Но если B определяются как

public void B(Something x) { } 

Тогда B(x) может быть устранен с помощью оптимизатора, а затем GC.KeepAlive(x) вызова может быть необходим вместо этого.

Может ли эта оптимизация выполняться JITter?

Существуют ли другие оптимизации, которые могут иметь видимые побочные эффекты, кроме изменений трассировки стека?

+2

Почему в мире вам нужно было бы «х» жить, если он больше не используется? –

+0

Для хорошей статьи по оптимизации JIT вы найдете http://www.codeproject.com/KB/dotnet/JITOptimizations.aspx - JITer может оптимизировать пропущенные вызовы методов, но будет поддерживать сами методы – BrokenGlass

+1

@JSBangs: причина, по которой вы может хотеть сохранить что-то живое, потому что его разрушение вызывает неуправляемый код для работы в нежелательном месте. Например, существуют объекты хранения COM, которые требуют, чтобы «внутренние» хранилища (думаю, вложенные каталоги) были закрыты * перед * «внешними» хранилищами, которые их содержат. Сборщик мусора может определить, что управляемый объект, который представляет собой внешнее хранилище, больше не используется и решает очистить его до того, как внутреннее хранилище, которое все еще жив, очищено. Я на практике должен был написать код, чтобы справиться с этой ситуацией, и это настоящая боль. –

ответ

6

При вызове A (x) x гарантированно сохраняется в конце A - поскольку B использует тот же параметр.

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


Может ли эта оптимизация (а именно, делать раннюю очистку ссылки, которая не используется в любом месте) на самом деле быть сделано джиттер?

Да, и на практике это делается. Это не наблюдаемый побочный эффект.

Это оправдан разделом 3.9 спецификации, которые я цитирую для вашего удобства:

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


Может оптимизация сделано с помощью C# компилятора или джиттера имеет видимые побочные эффекты?

Ваш вопрос отвечает в разделе 3.10 спецификации, которые я привожу здесь для вашего удобства:

Исполнение C# программы продолжается такие, что побочные эффекты каждого выполняющегося потока сохраняются на критических точек выполнения.

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

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

Среда выполнения вольна изменений в порядке исполнения программы в C# , с учетом следующих ограничений :

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

Правила порядка инициализации: сохранен.

Сохранение порядка побочных эффектов относительно неустойчивых чтений и пишет.

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

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

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

Обратите внимание, что в частности зависимость данных сохраняется только в пределах нить исполнения. Зависимость от данных не гарантированно сохраняется при наблюдении из другого потока выполнения.

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

+0

Поскольку я передаю аргумент 'B', хотя он не используется внутри этого метода, я, хотя' x' будет считаться живым, по крайней мере, до тех пор, пока не будет введен B. Я ошибся? – configurator

+0

@configurator Я предполагаю, что JIT может видеть, что метод ничего не делает и полностью исключает метод и все обращения к нему. – Davy8

+0

@configurator: Как ясно говорится в разделе 3.9, дрожание не обязано рассматривать содержимое х живым, если х не доказывает, что он никогда не читается прошлой точкой. Джиттер не обязан считать его мертвым. Это оптимизация, определяемая реализацией. –

8

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

Для того чтобы быть видимыми побочными эффектами, они должны быть видны программе, а не внешнему инструменту, например отладчику или объекту.

0

Включая B в свой вопрос, просто смущает вопрос. Учитывая этот код:

var x = new Something(); 
A(x); 

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

Вы должны определить, что вы подразумеваете под «видимыми побочными эффектами». Можно надеяться, что оптимизация JITer, по крайней мере, будет иметь побочный эффект, заключающийся в том, что ваш код будет меньше или быстрее. Являются ли эти «видимыми»? Или вы имеете в виду «нежелательный»?

0

Eric Lippert начал отличную серию о рефакторинге, которая заставляет меня поверить, что компилятор C# и JITter не должны вводить побочные эффекты. Part 1 и Part 2 в настоящее время онлайн.

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