本文由 简悦 SimpRead 转码, 原文地址 https://www.toutiao.com/i6732361325244056072/

作者:Hollis
来源:公众号Hollis 

Java 作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的 JVM 内存结构Java 内存模型Java 对象模型,这就是三个截然不同的概念,但是很多人容易弄混。

可以这样说,很多高级开发甚至都搞不不清楚 JVM 内存结构、Java 内存模型和 Java 对象模型这三者的概念及其间的区别。甚至我见过有些面试官自己也搞的不是太清楚。不信的话,你去网上搜索 Java 内存模型,还会有很多文章的内容其实介绍的是 JVM 内存结构。

首先,这三个概念是完全不同的三个概念。本文主要对这三个概念加以区分以及简单介绍。其中每一个知识点都可以单独写一篇文章,本文并不会深入介绍,感兴趣的朋友可以加入我的知识星球和球友们共同学习。

JVM 内存结构

我们都知道,Java 代码是要运行在虚拟机上的,而虚拟机在执行 Java 程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。

其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《Java 虚拟机规范(Java SE 8)》中描述了 JVM 运行时内存区域结构如下:

各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点:

1、以上是 Java 虚拟机规范,不同的虚拟机实现会各有不同,但是一般会遵守规范。

2、规范中定义的方法区,只是一种概念上的区域,并说明了其应该具有什么功能。但是并没有规定这个区域到底应该处于何处。所以,对于不同的虚拟机实现来说,是有一定的自由度的。

3、不同版本的方法区所处位置不同,上图中划分的是逻辑区域,并不是绝对意义上的物理区域。因为某些版本的 JDK 中方法区其实是在堆中实现的。

4、运行时常量池用于存放编译期生成的各种字面量和符号应用。但是,Java 语言并不要求常量只有在编译期才能产生。比如在运行期,String.intern 也会把新的常量放入池中。

5、除了以上介绍的 JVM 运行时内存外,还有一块内存区域可供使用,那就是直接内存。Java 虚拟机规范并没有定义这块内存区域,所以他并不由 JVM 管理,是利用本地方法库直接在堆外申请的内存区域。

6、堆和栈的数据划分也不是绝对的,如 HotSpot 的 JIT 会针对对象分配做相应的优化。

如上,做个总结,JVM 内存结构,由 Java 虚拟机规范定义。描述的是 Java 程序执行过程中,由 JVM 管理的不同数据区域。各个区域有其特定的功能。

Java 内存模型

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 是一种面向对象的语言,而 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 对象在虚拟机中的表现形式有关。

关于这三部分内容,本文并未分别展开,因为涉及到的知识点实在太多,如果读者感兴趣,可以自行学习。后面也会发文介绍这些内容,敬请期待。

最后,这三个概念非常重要,一定要严格区分开,千万不要在面试中出现答非所为的情况。

区分 JVM 内存结构、 Java 内存模型 以及 Java 对象模型 三个概念的更多相关文章

  1. JVM内存区域的划分(内存结构或者内存模型)

    JVM内存区域的划分(内存结构或者内存模型)   运行时数据区域: 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 程序计数器(线程私有): 是当前线程所 ...

  2. JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)

    一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...

  3. 面试突击(八)——JVM的结构及内存模型,是怎么划分的?

    声明:本文图片均来自网络,我只是进行了选择,利用一图胜千言的力量来帮助自己快速的回忆相关的知识点 0:再上一张Java代码的转换流程图 .java——Java程序员编写,给人看的 .class——Ja ...

  4. struct class 内存结构初探-内存模型顺序和变量的实际添加顺序一致

    typedef struct structTest { char xchar; int xint; int yint; }xStruct; @interface ViewController () { ...

  5. 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型

    原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...

  6. 【转】JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...

  7. Java内存模型、JVM内存结构和Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存 ...

  8. [转帖]JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 VS Java内存模型 VS Java对象模型 https://www.hollischuang.com/archives/2509 Java作为一种面向对象的,跨平台语言,其对象.内 ...

  9. JVM内存结构、Java内存模型和Java对象模型

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚.比如本文要讨论的JVM内存结构.Java内存模型和Java对象模型 ...

随机推荐

  1. python 实例方法、静态方法、类方法

    class Date: #构造函数 def __init__(self, year, month, day): self.year = year self.month = month self.day ...

  2. ansible命令参数介绍

    -m:要执行的模块,默认为command -a:模块的参数 -u:ssh连接的用户名,默认用root,ansible.cfg中可以配置 -k:提示输入ssh登录密码.当使用密码验证的时候用 -s:su ...

  3. Java8的Stream方法findAny空指针异常(NullPointerException)实例对比

    实战介绍 学习完Java8的Stream方法,可能你正准备大展身手,却发现遇到不少问题,本篇文章为大家带来一个findAny方法抛出java.lang.NullPointerException的场景. ...

  4. 数据库之MySQL查询

    查询 创建数据库.数据表 -- 创建数据库 create database python_test1 charset=utf8; -- 使用数据库 use python_test1; -- stude ...

  5. SpringBoot(16)—@ConditionalOnBean与@ConditionalOnClass

    @ConditionalOnBean与@ConditionalOnClass 上一篇讲的@Conditional可以通过条件控制是否注入Bean,这篇讲下有关Bean其它几个常用的注解使用方式 @Co ...

  6. Spring Boot 中如何支持异步方法

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  7. 高效取余运算(n-1)&hash原理探讨

    Java的HashMap源码中用到的(n-1)&hash这样的运算,查找发现这是一种高效的求余数的办法,但其中的原理是什么呢为什么可以这么做呢? 先上结论:假设被除数是x,对于除数是2n的取余 ...

  8. python+requests+re匹配抓取猫眼上映电影信息

    python+requests抓取猫眼中上映电影,re正则匹配获取对应电影的排名,图片地址,片名,主演及上映时间和评分 import requests import re, json def get_ ...

  9. postman---postman自动发博客

    前面写了一篇如何通过Cookies值去登录博客园,今天我们来通过登录博客园之后,我们进行通过Postman自动写博客 自动写博客 1.打开Postman.填写博客园对应的Cookies: 2.抓取编写 ...

  10. (转)深入浅出JWT(JSON Web token)

    转载地址:https://www.cnblogs.com/mantoudev/p/8994341.html 参考地址:https://baijiahao.baidu.com/s?id=16080218 ...