电子说
在上一篇文章中,我们了解了计算机由于各个硬件的读取速度之间的巨大差距,和充分利用CPU的性能的手段方法,及其所带来的一系列问题:
有序性问题
。可见性问题
原子性问题
。Java 是最早尝试提供内存模型的编程语言。由于Java 语言是跨平台的,另外各个操作系统总存在一些差异,Java在物理机器的基础上抽象出一个内存模型(JMM)
JMM 可以看作是 Java 定义的并发编程相关的一组规范,除了抽象了线程和主内存之间的关系之外,其还规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,这样就可以屏蔽各个操作系统的差异,简化多线程编程。
这是一个非常容易让人混淆的问题,Java 内存区域和内存模型完全是不一样的东西,
Java 内存区域
, 也叫内存区域
、JVM内存模型
,和 Java 虚拟机(JVM)的运行时区域相关,是指 JVM运行时将数据分区域存储,强调对内存空间的划分。Java内存模型
,也叫内存模型(JMM)
,是Java 定义的并发编程相关的一组规范,除了抽象了线程和主内存之间的关系之外,其还规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,屏蔽各个操作系统的差异。通俗点说: JMM规范了程序中变量的访问规则,保证了操作的原子性、可见性、有序性, 我们下文慢慢道来。我们知道JVM 运行时内存区域是分区域的,分为栈、堆等,其实这些都是 JVM 定义的逻辑概念。但在传统的硬件内存架构中是没有栈和堆这种概念。
其中:
虚拟机栈(JVM Stacks)
和 本地方法栈(Native Method Stack)
JNI(Java Native Interface)
来访问虚拟机运行时的数据区,甚至可以调用寄存器,具有和 JVM 相同的能力和权限。JNI 类本地方法最著名的应该是 System.currentTimeMillis()
虚拟机堆是Java虚拟机中内存最大的一块,是被所有线程共享的,在虚拟机启动时候创建,Java堆唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配、标量替换优化的技术将会导致一些微妙的变化,所有的对象都分配在堆上渐渐变得不那么“绝对”了。
Java中栈和堆
既存在于计算机的高速缓存中,又存在于主存
中,所以两者并没有很直接的关系。
Java 内存模型(JMM) 抽象了线程和主内存之间的关系,就比如说线程之间的共享变量必须存储在主内存中。在 JDK1.2 之前,Java 的内存模型实现总是从 主存 (即共享内存)读取变量,是不需要进行特别的注意的。而在当前的 Java 内存模型下,线程可以把变量保存 本地内存 (比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
JMM
抽象出来的一个概念,存储了主内存中的共享变量副本。Java 内存模型其实是一种规范,定义了很多东西:
这里所讲的主内存、工作内存与 Java 内存区域中的 Java 堆、栈、方法区等并不是同一个层次的内存划分,这两者基本上是没有关系的,如果两者一定要勉强对应起来,那从变量、主内存、工作内存的定义来看,主内存主要对应于Java堆中的对象实例数据部分,而工作内存则对应于虚拟机栈中的部分区域。
全部0条评论
快来发表一下你的评论吧 !