C#优化和副作用

con*_*tor 5 c# optimization jit

C#编译器或JITter可以进行优化会产生明显的副作用吗?

我已经离开了一个例子.

var x = new Something();
A(x);
B(x);
Run Code Online (Sandbox Code Playgroud)

当调用A(x) x是保证,更让在2002年底A-因为B使用相同的参数.但如果B被定义为

public void B(Something x) { }
Run Code Online (Sandbox Code Playgroud)

然后B(x)可以通过优化器消除,然后GC.KeepAlive(x)可能需要调用.

这个优化实际上可以由JITter完成吗?

除了堆栈跟踪更改之外,是否存在可能具有可见副作用的其他优化?

Zan*_*ynx 8

如果你的函数B没有使用参数x,那么消除它并提前收集x 没有任何可见的副作用.

要成为"可见的副作用",它们必须对程序可见,而不是对调试器或对象查看器等外部工具可见.


Eri*_*ert 6

当调用A(x)x时,保证在A的末尾保持活动状态 - 因为B使用相同的参数.

这句话是错误的.假设方法A总是抛出异常.抖动可能知道B永远不会到达,因此x可以立即释放.假设方法A在最后一次引用x之后进入无条件无限循环; 再次,抖动可以知道通过静态分析,确定x将永远不会被再次引用,并安排它被清理.我不知道抖动是否实际执行了这些优化; 他们似乎很狡猾,但他们是合法的.


这种优化(即,尽早清理未在任何地方使用的引用)实际上可以由JITter完成吗?

是的,在实践中,它已经完成.这不是一个可观察到的副作用.

这可以通过规范的第3.9节来证明,为方便起见我引用它:

如果对象或其任何部分无法通过任何可能的继续执行来访问,除了运行析构函数之外,该对象被认为不再使用,并且它有资格进行销毁.C#编译器和垃圾收集器可以选择分析代码以确定将来可以使用对对象的哪些引用.例如,如果范围内的局部变量是对象的唯一现有引用,但该过程中当前执行点的任何可能的继续执行中从不引用该局部变量,则垃圾收集器可能(但是不要求将对象视为不再使用.


C#编译器或JITter可以进行优化会产生明显的副作用吗?

您的问题在规范的第3.10节中得到了解答,为方便起见,我在此引用:

执行C#程序,以便在关键执行点保留每个执行线程的副作用.

副作用定义为易失性字段的读取或写入,对非易失性变量的写入,对外部资源的写入以及抛出异常.

必须保留这些副作用的顺序的关键执行点是对volatile字段,锁定语句以及线程创建和终止的引用.

执行环境可以自由更改C#程序的执行顺序,但受以下限制:

数据依赖性保留在执行的线程中.也就是说,计算每个变量的值,就好像线程中的所有语句都以原始程序顺序执行一样.

保留初始化排序规则.

关于易失性读取和写入,保留了副作用的顺序.

此外,执行环境不需要评估表达式的一部分,如果它可以推断出不使用该表达式的值并且不产生所需的副作用(包括由调用方法或访问volatile字段引起的任何副作用).

当程序执行被异步事件(例如另一个线程抛出的异常)中断时,不能保证可观察的副作用在原始程序顺序中可见.

倒数第二段是我相信你最关心的一段; 也就是说,在影响可观察的副作用方面,允许运行时的优化是什么?允许运行时执行任何不影响可观察副作用的优化.

请注意,特别是数据依赖性仅保留执行的线程中.从另一个执行线程观察时,保证保留数据依赖性.

如果这不能回答您的问题,请提出更具体的问题.特别是,如果您不考虑上面给出的定义以匹配您对"可观察到的副作用"的定义,则需要仔细而精确地定义"可观察到的副作用"以更详细地回答您的问题.