我们都知道堆栈和堆的想法,但我最近读到了第三个保存数据的选项:寄存器。
我很难找到关于这种类型的好文章,我发现的是:http://www.dotnetperls.com/method-parameter,以及C的很多内容,例如:http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/
到目前为止我唯一真实的信息:每个CPU都有自己的寄存器,可以用来保存数据,以最快的方式访问,例如在for循环中。
据我所知,此注册是由CLR完成的。然后我想起了这个volatile-keyword,如果我们看一下MSDN:
volatile关键字表示字段可能被修改 多个线程同时执行。是的领域 声明的volatile不受编译器优化的限制 假设由单个线程访问。这确保了最多 字段中始终存在最新值。
Volatile也是如此?它告诉CLR不要使用CPU寄存器而是堆栈/堆,它可以被所有CPU /线程访问?
我很抱歉这个令人困惑的问题,但关于这个话题的信息确实很少。
答案 0 :(得分:4)
这句话具有误导性,因为它不是对波动性保证的准确定义。在编译器优化方面未指定Volatile。此外,在ARM上限制编译器是不够的。 CPU也必须受到限制。我建议你研究一下volatile的确切含义。
volatile甚至不能阻止使用寄存器。易失性负载保证读取volatile变量的次数与程序执行的次数完全相同,并且顺序相同。
当你写:
volatile int sharedVar = 0;
Console.WriteLine(sharedVar);
Console.WriteLine(sharedVar);
JIT必须正好读两遍。但它仍然可以使用寄存器来存储读取的值。
如果CLR可以证明永远不会写入sharedVar
并且始终具有值0
,它甚至可以删除读取。它可能必须在某些地方插入内存屏障而不是读取,因为volatile
访问具有某些排序保证。但是根本没有负载必须完全发生。 (当前的JIT不进行此优化。)
寄存器是一个实现细节。 CLR未在物理实现方面指定。我知道您想了解实施细节,这很好。但是,对于CLR保证程序员的内容,它们并不重要。
答案 1 :(得分:3)
“每个CPU都有自己的注册表”
每个CPU都有一组寄存器,用于涉及任何数据的大多数操作。通常,指令将一些数据从存储器加载到寄存器中,然后另一条指令对寄存器中的数据进行一些计算。
CPU有一些用于数据的寄存器,一些用于指针的寄存器,以及一些跟踪程序执行的特殊寄存器,如指令指针,堆栈指针和标志寄存器。
由于CPU有多个寄存器,JIT编译器有时可以使用其中一些寄存器作为局部变量的存储。寄存器不是在堆栈上分配变量,而是专用于保存变量的值。
volatile
关键字不会影响寄存器的存储方式。如果一个变量可以被不同的线程访问,那么它不是那种存储在寄存器中的候选变量。实际上,它只是具有有限范围和短寿命的局部变量,将存储在寄存器中。