Java内存模型和Java内存区域的区别和联系

小编 270

Java内存模型和Java内存区域的区别在于:内存模型定义了线程和主内存之间的抽象关系,即JVM在计算机内存(RAM)中的工作方式;而内存区域是指JVM运行时将数据分区域存储,强调对内存空间的划分。两者之间没有必然的联系,只是都存在共享数据区域和私有数据区域。

1.Java内存模型

Java内存模型是根据英文“Java Memory Model”翻译而来,简称JMM,其本身是一种抽象的概念,并不真实存在。内存模型定义了线程和主内存之间的抽象关系,即JVM在计算机内存(RAM)中的工作方式。

Java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量(堆内存中的实例域,静态域和数组元素)来完成隐式通信。它控制着Java线程之间的通信,决定一个线程对共享变量的写入何时对另一个线程可见。

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量(线程共享的变量)存储到内存和从内存中取出变量这样底层细节。Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。

2.Java内存区域

Java内存区域是指JVM运行时将数据分区域存储,简单的说就是不同的数据放在不同的地方,因此又叫“运行时数据区域”。

根据《Java虚拟机规范的规定》,Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

(1)方法区(公有):又称Non-Heap(非堆),主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。

(2)运行时常量池:它是方法区的一部分,主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用。

(3)Java堆(公有):也是属于线程共享的内存区域,对于Java应用程序来说,它是虚拟机所管理的内存中最大的一块区域,Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存存在的少数目的就是存放对象实例,几乎所有的对象实例都在堆上分配空间、存放。

(4)虚拟机栈(线程私有):线程同时创建,总数与线程关联,代表Java方法执行的内存模型。每个方法执行时都会创建一个栈桢来存储方法的的变量表、操作数栈、动态链接方法、返回值、返回地址等信息。

(5)程序计数器(线程私有):属于线程私有的数据区域,是一小块内存空间,主要代表当前线程所执行的字节码行号指示器。字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

(6)本地方法栈(线程私有):主要与虚拟机用到的Native方法相关,是为虚拟机使用到的本地(Native)方法服务。对应本地方法栈的实现,《Java虚拟机规范》中并未强制规定,由虚拟机自己根据需求实现,有的Java虚拟机例如Hot-Spot虚拟机就直接将本地方法栈和虚拟机栈合二为一。

延伸阅读

Java内存模型的三大特性是什么

1.原子性

原子性表示线程在操作变量时,要不全部成功,要不全部失败,没有中间状态。也就是说现在有两个线程,线程A,线程B。线程A在对data变量做++(或者其他)操作的时候,线程B是没有办法影响到线程A的这个操作。只有当线程A做完了这个操作之后,线程B才能够对data变量做其他的操作。

但是比较遗憾的是,因为在多线程中,线程操作都是都是工作内存中的变量数据,在这种线程隔离的情况下,是不具备原子性的。也就是说线程A跟线程B是同时可以操作data变量。如线程A在对data变量做“++”操作的时候,线程B同样可以对data变量做“++”操作。所以我们需要借助其他的方式来保证原子性。

2.可见性

可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。

Java提供了volatile关键字来保证可见性。当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。

3.有序性

有序性指的是从源代码到编译运行的过程中,会有多种重排序的指令发生。重排序的目的是为了更快的去执行代码,提高代码效率。但是在多线程的情况下,胡乱的重排序会导致最终的运行结果跟原始代码运行的结果不一样。这样的代码部署到生产环境很容易造成重大事故。而有序性就是为了解决这种问题,禁止重排序来保证程序的顺序执行。

回复

我来回复
  • 暂无回复内容

注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部