Java 作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的 JVM 内存结构、Java 内存模型和 J****ava 对象模型,这就是三个截然不同的概念,但是很多人容易弄混。
可以这样说,很多高级开发甚至都搞不不清楚 JVM 内存结构、Java 内存模型和 Java 对象模型这三者的概念及其间的区别。甚至我见过有些面试官自己也搞的不是太清楚。不信的话,你去网上搜索 Java 内存模型,还会有很多文章的内容其实介绍的是 JVM 内存结构。
首先,这三个概念是完全不同的三个概念。本文主要对这三个概念加以区分以及简单介绍。其中每一个知识点都可以单独写一篇文章,本文并不会深入介绍,感兴趣的朋友可以加入我的知识星球和球友们共同学习。
我们都知道,Java 代码是要运行在虚拟机上的,而虚拟机在执行 Java 程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。
其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《Java 虚拟机规范(Java SE 8)》中描述了 JVM 运行时内存区域结构如下:
各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点:
如上,做个总结,JVM 内存结构,由 Java 虚拟机规范定义。描述的是 Java 程序执行过程中,由 JVM 管理的不同数据区域。各个区域有其特定的功能。
Java 内存模型看上去和 Java 内存结构(JVM 内存结构)差不多,很多人会误以为两者是一回事儿,这也就导致面试过程中经常答非所为。
在前面的关于 JVM 的内存结构的图中,我们可以看到,其中 Java 堆和方法区的区域是多个线程共享的数据区域。也就是说,多个线程可能可以操作保存在堆或者方法区中的同一个数据。这也就是我们常说的 “Java 的线程间通过共享内存进行通信”。
Java 内存模型是根据英文 Java Memory Model(JMM)翻译过来的。其实 JMM 并不像 JVM 内存结构一样是真实存在的。他只是一个抽象的概念。JSR-133: Java Memory Model and Thread Specification 中描述了,JMM 是和多线程相关的,他描述了一组规则或规范,这个规范定义了一个线程对共享变量的写入时对另一个线程是可见的。
那么,简单总结下,Java 的多线程之间是通过共享内存进行通信的,而由于采用共享内存进行通信,在通信过程中会存在一系列如可见性、原子性、顺序性等问题,而 JMM 就是围绕着多线程通信以及与其相关的一系列特性而建立的模型。JMM 定义了一些语法集,这些语法集映射到 Java 语言中就是 volatile、synchronized 等关键字。
在 JMM 中,我们把多个线程间通信的共享内存称之为主内存,而在并发编程中多个线程都维护了一个自己的本地内存(这是个抽象概念),其中保存的数据是主内存中的数据拷贝。而 JMM 主要是控制本地内存和主内存之间的数据交互的。
在 Java 中,JMM 是一个非常重要的概念,正是由于有了 JMM,Java 的并发编程才能避免很多问题。这里就不对 Java 内存模型做更加详细的介绍了,想了解更多的朋友可以参考《Java 并发编程的艺术》。
Java 是一种面向对象的语言,而 Java 对象在 JVM 中的存储也是有一定的结构的。而这个关于 Java 对象自身的存储模型称之为 Java 对象模型。
HotSpot 虚拟机中,设计了一个 OOP-Klass Model。OOP(Ordinary Object Pointer)指的是普通对象指针,而 Klass 用来描述对象实例的具体类型。
每一个 Java 类,在被 JVM 加载的时候,JVM 会给这个类创建一个instanceKlass
,保存在方法区,用来在 JVM 层表示该 Java 类。当我们在 Java 代码中,使用 new 创建一个对象的时候,JVM 会创建一个instanceOopDesc
对象,这个对象中包含了对象头以及实例数据。
这就是一个简单的 Java 对象的 OOP-Klass 模型,即 Java 对象模型。
我们再来区分下 JVM 内存结构、 Java 内存模型 以及 Java 对象模型 三个概念。
JVM 内存结构,和 Java 虚拟机的运行时区域有关。
Java 内存模型,和 Java 的并发编程有关。
Java 对象模型,和 Java 对象在虚拟机中的表现形式有关。
最后,这三个概念非常重要,一定要严格区分开,千万不要在面试中出现答非所为的情况。
作者:Hollis,阿里资深攻城狮
来自:Hollis