内存模型

内存模型

如前文所述,现代计算机通常有两个或者更多的 CPU,一些 CPU 还有多个核;其允许多个线程同时运行,每个 CPU 在某个时间片内运行其中的一个线程。在《存储管理》一节中我们介绍了计算机系统中的不同的存储类别:

多层次存储器

每个 CPU 包含多个寄存器,这些寄存器本质上就是 CPU 内存;CPU 在寄存器中执行操作的速度会比在主内存中操作快非常多。每个 CPU 可能还拥有 CPU 缓存层,CPU 访问缓存层的速度比访问主内存块很多,但是却比访问寄存器要慢。计算机还包括主内存(RAM),所有的 CPU 都可以访问这个主内存,主内存一般都比 CPU 缓存大很多,但速度要比 CPU 缓存慢。当一个 CPU 需要访问主内存的时候,会把主内存中的部分数据读取到 CPU 缓存,甚至进一步把缓存中的部分数据读取到内部的寄存器,然后对其进行操作。当 CPU 需要向主内存写数据的时候,会将寄存器中的数据写入缓存,某些时候会将数据从缓存刷入主内存。无论从缓存读还是写数据,都没有必要一次性全部读出或者写入,而是仅对部分数据进行操作。

从 CPU 到 大约需要的 CPU 周期 大约需要的时间
主存 - 约 60-80ns
QPI 总线传输(between sockets, not drawn) - 约 20ns
L3 cache 约 40-45 cycles 约 15ns
L2 cache 约 10 cycles 约 3ns
L1 cache 约 3-4 cycles 约 1ns
寄存器 1 cycle -

并发编程中的问题,往往源于缓存导致的可见性问题、线程切换导致的原子性问题以及编译优化带来的有序性问题。以 Java 虚拟机为例,每个线程都拥有一个属于自己的线程栈(调用栈),随着线程代码的执行,调用栈会随之改变。线程栈中包含每个正在执行的方法的局部变量。每个线程只能访问属于自己的栈。调用栈中的局部变量,只有创建这个栈的线程才可以访问,其他线程都不能访问。即使两个线程在执行一段相同的代码,这两个线程也会在属于各自的线程栈中创建局部变量。因此,每个线程拥有属于自己的局部变量。所有基本类型的局部变量全部存放在线程栈中,对其他线程不可见。一个线程可以把基本类型拷贝到其他线程,但是不能共享给其他线程,而无论哪个线程创建的对象都存放在堆中。

在内存模型中我们可能会涉及到如下相关的概念术语:

概念术语图