静态变量存储在非静态方法调用中的什么位置? IE。在 CalculateTotalStatic()
中,我们递增静态成员 MyStaticVariableHolder.Total
并且还将变量 i
与 MyStaticVariableHolder.TotalArray 进行比较。 for 循环内的长度
。
另一方面,在此方法的另一个版本 CalculateTotalLocal()
中,我们使用在方法中声明的局部变量来执行上述两个操作。
在 CalculateTotalLocal
期间,将有两个额外的变量放置在堆栈上,它们会将它们的值保存在堆栈本身(localTotal
和 localLength
)。 CalculateTotalStatic
会发生什么?它是否每次都从堆中访问静态变量?此外,CalculateTotalLocal
比 CalculateTotalStatic
快 10%。这种性能提升的正确原因是什么?
编辑 - 我想我不是很清楚 - 对此表示歉意。
我想说的是:
能否(根据 C# 规范)通过兼容的 C# 编译器/JIT 以与局部变量相同的方式优化静态变量访问?
class MyStaticVariableHolder
{
public static int[] TotalArray = new int[100];
public static int Total = 1;
}
class Trial
{
public void CalculateTotalStatic()
{
for (int i = 0; i < MyStaticVariableHolder.TotalArray.Length; i++)
{
MyStaticVariableHolder.Total += i;
}
}
public void CalculateTotalLocal()
{
int localTotal = MyStaticVariableHolder.Total;
int[] localTotalArray = MyStaticVariableHolder.TotalArray;
int localLength = MyStaticVariableHolder.TotalArray.Length;
for (int i = 0; i < localLength; i++)
{
localTotal += i;
}
MyStaticVariableHolder.Total = localTotal;
}
}
我也在看这个链接 - http://www.dotnetperls.com/local-variable-field-optimization供引用,但我没有达到他们所获得的性能提升。
最佳答案
Where are static variables stored inside a non static method call?
我认为你的意思是:从静态变量中获取一个值,以便对其执行一些计算。因此,复制了该值。复制到什么存储空间?
在 IL 级别,它被纳入评估堆栈。运行时具有广泛的自由度来具体化评估堆栈,但它喜欢。当前线程的栈,或者寄存器都有可能。
我注意到在某些情况下可以将副本复制到堆位置。
What happens in the case of CalculateTotalStatic? Does it access the static variables from the heap every time?
等等,谁说他们一开始就在堆上?不需要将静态变量存储在垃圾收集堆上。他们的内存不会被收集,那么他们为什么要在堆上呢? (变量引用的数组当然在堆上。)
我们换个说法。
What happens in the case of CalculateTotalStatic? Does it do a fresh access to the static variable every time?
这个问题仍然没有答案。再次改写。
Is the runtime required to do a fresh fetch from the variable every time?
没有。允许运行时执行在单线程程序中不可见的任何优化。 (这有点夸大其词;有一些优化它不会执行。我不会列出它们是什么。)内化这个事实。在单线程程序中,除非移动,否则一切都是稳定的。在多线程程序中,除非保持静止,否则一切都在移动。即使在后者为真的世界中,运行时也可以假设前者。
Also, CalculateTotalLocal is 10% faster than CalculateTotalStatic. What is the correct reason for this performance improvement?
我不知道。检查生成的代码,看看有什么区别。
can (according to C# spec) static variable access be optimized the same way as local variable by compliant C# compiler/JIT?
绝对是的。这完全属于“在单线程程序中不可见的任何优化”。
此外:运行时不仅允许重新排序读取和写入,因为它认为合适。还允许不同的线程观察不一致的世界。如果一个线程观察到特定时间序列的变量被读取和写入,则允许另一个线程观察完全不同的读取和写入交错。
此外:不要忘记运行时我的意思是运行时所依赖的任何东西,比如CPU。请记住,CPU 被允许在他们认为合适的时候重新排序读取和写入。仅仅因为您正在查看一些 x86 代码,该代码明确地将内存中的位置读取到寄存器中,这与读取实际进入内存的时间绝对没有任何关系。该内存位置可能已经在缓存中,并且主内存可能已经写入另一个线程,从而有效地将读取时间向后移动。
此外: volatile 不一定有帮助。对于那些相信他们可以正确预测在 strong 内存模型上只能对静态变量进行 volatile 访问的程序的行为的人,我鼓励您阅读 http://blog.coverity.com/2014/03/26/reordering-optimizations/看看你是否能正确推断出允许的读写序列。请记住,这是基于 strong 内存模型的;现在想想在弱内存模型上可能会有多困难!
当您放弃跨线程共享内存的标准模式和实践时,您就陷入了困境。不要去那里。
关于c# - 局部变量与静态变量内存和性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35705878/