CodeGym/Java 课程/模块 3/JVM 中的内存,第 2 部分

JVM 中的内存,第 2 部分

可用

内存硬件架构

现代内存硬件架构不同于 Java 的内部内存模型。因此,您需要了解硬件体系结构才能了解 Java 模型如何与它一起工作。本节介绍一般内存硬件架构,下一节介绍 Java 如何使用它。

这是现代计算机硬件架构的简化图:

内存硬件架构

在现代世界,一台计算机有 2 个或更多处理器,这已经是常态。其中一些处理器可能还具有多个内核。在这样的计算机上,可以同时运行多个线程。每个处理器核心都能够在任何给定时间执行一个线程。这意味着任何 Java 应用程序都是先验多线程的,并且在您的程序中,每个处理器内核可以同时运行一个线程。

处理器内核包含一组驻留在其内存中(内核内部)的寄存器。它对寄存器数据执行操作的速度比对驻留在计算机主内存 (RAM) 中的数据快得多。这是因为处理器可以更快地访问这些寄存器。

每个 CPU 也可以有自己的缓存层。大多数现代处理器都有它。处理器访问其高速缓存的速度比主存快得多,但不如其内部寄存器快。高速缓存访​​问速度的值大约介于主存储器和内部寄存器的访问速度之间。

此外,处理器有一个地方可以拥有多级缓存。但是为了理解 Java 内存模型如何与硬件内存交互,了解这一点并不重要。重要的是要知道处理器可能具有某种级别的高速缓存。

任何计算机也以相同的方式包含 RAM(主内存区域)。所有内核都可以访问主内存。主内存区域通常比处理器内核的缓存内存大得多。

在处理器需要访问主内存的那一刻,它会将其中的一部分读入其高速缓存中。它还可以从缓存中读取一些数据到其内部寄存器中,然后对其进行操作。当 CPU 需要将结果写回主存时,它会将数据从其内部寄存器刷新到高速缓存,并在某个时候刷新到主存。

当处理器需要在缓存中存储其他内容时,缓存中存储的数据通常会刷新回主内存。缓存具有清除内存和同时写入数据的能力。处理器不需要在每次更新期间都读取或写入完整的缓存。通常缓存在小块内存中更新,它们被称为“缓存行”。一个或多个“高速缓存行”可被读入高速缓存存储器,并且一个或多个高速缓存行可被刷新回主存储器。

结合Java内存模型和内存硬件架构

正如已经提到的,Java 内存模型和内存硬件架构是不同的。硬件架构不区分线程栈和堆。在硬件上,线程堆栈和 HEAP(堆)驻留在主内存中。

部分堆栈和线程堆有时可能会出现在 CPU 的高速缓存和内部寄存器中。如图所示:

线程堆栈和堆

当对象和变量可以存储在计算机内存的不同区域时,就会出现某些问题。这是两个主要的:

  • 线程对共享变量所做更改的可见性。
  • 读取、检查和写入共享变量时的竞争条件。

下面将对这两个问题进行解释。

共享对象的可见性

如果两个或多个线程在没有正确使用 volatile 声明或同步的情况下共享一个对象,则一个线程对共享对象所做的更改可能对其他线程不可见。

想象一下,一个共享对象最初存储在主内存中。在一个 CPU 上运行的线程将共享对象读入同一个 CPU 的缓存中。他在那里对对象进行了更改。在 CPU 的高速缓存被刷新到主内存之前,共享对象的修改版本对于在其他 CPU 上运行的线程是不可见的。这样,每个线程都可以获得自己的共享对象副本,每个副本都会在单独的 CPU 缓存中。

下图说明了这种情况的概要。在左侧 CPU 上运行的一个线程将共享对象复制到它的缓存中,并将计数的值更改为 2。此更改对在右侧 CPU 上运行的其他线程是不可见的,因为对计数的更新尚未刷新回主内存。

要解决这个问题,可以在声明变量时使用volatile关键字。它可以确保给定的变量直接从主存中读取,并且在更新时总是写回主存。

竞争条件

如果两个或多个线程共享同一个对象并且多个线程更新该共享对象中的变量,则可能会出现竞争条件。

假设线程 A 将共享对象的计数变量读入其处理器的缓存中。还想象一下线程 B 做同样的事情,但是在另一个处理器的缓存中。现在线程 A 将 count 的值加 1,线程 B 也做同样的事情。现在变量已经增加了两次 - 在每个处理器的缓存中分别增加了 +1。

如果按顺序执行这些增量,则计数变量将加倍并写回主内存(原始值 + 2)。

但是,在没有适当同步的情况下同时执行了两个增量。无论哪个线程(A 或 B)将其更新版本的 count 写入主存,新值只会比原始值多 1,尽管增加了两次。

此图说明了上述竞争条件问题的发生:

要解决这个问题,可以使用 Java 同步块。同步块确保在任何给定时间只有一个线程可以进入给定的代码关键部分。

同步块还保证所有在同步块内部访问的变量都会从主存中读取,并且当线程退出同步块时,所有更新的变量都会被刷新回主存,不管变量是声明为volatile还是否。

评论
  • 受欢迎
你必须先登录才能发表评论
此页面还没有任何评论