Java内存模型与JVM运行时数据区的区别

首先,这两者是完全不同的概念,绝对不能混为一谈。

1.什么是Java内存模型?

Java内存模型是Java语言在多线程并发情况下对于共享变量读写(实际是共享变量对应的内存操作)的规范,主要是为了解决多线程可见性、原子性的问题,解决共享变量的多线程操作冲突问题。

多线程编程的普遍问题是:

  • 所见非所得
  • 无法肉眼检测程序的准确性
  • 不同的运行平台表现不同
  • 错误很难复现

故JVM规范规定了Java虚拟机对多线程内存操作的一些规则,主要集中体现在volatile和synchronized这两个关键字。

  • volatile 是JVM提供的对共享变量在多线程读写时的可见性保证,主要作用是对volatile修饰的共享变量禁止被缓存(这里跟CPU的高速缓存和缓存一致性协议有关),不做重排序(重排序:在CPU处理速度远大于内存读写速度的现状下为了提高性能而进行的优化),但是并不保证共享变量操作的原子性。
  • synchronized 是JVM提供的锁机制,通过锁的特性和内存屏障保证锁住区域操作的原子性、可见性、有序性。
  • 锁争抢的是对象(static锁的是类对象,非static锁的是当前对象,即this,锁方法块锁的是自定义对象)在堆内存中对象头的一块内存的“主权”,只有一个线程能获取该“主权”,即排他性,通过锁的排他性保证对锁住区域的操作的原子性
  • 通过在代码前后加入加载屏障(Load?Barrier)和存储屏障(Store Barrier),能保证锁住代码块或者方法中对共享变量的操作的可见性
  • 通过在代码前后加入获取屏障(Acquire?Barrier)和释放屏障(Release?Barrier),能保证锁住代码块或者方法中对共享变量的操作的有序性

2.什么是JVM运行时数据区?

JVM运行时数据区,是Java虚拟机在运行时对该Java进程占用的内存进行的一种逻辑上的划分,包括方法区、堆内存、虚拟机栈、本地方法栈、程序计数器。这些区块实际都是Java进程在Java虚拟机的运作下通过不同数据结构来对申请到的内存进行不同使用。

  • 方法区:JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据。不同虚拟机有不同的实现,oracle的HotSpot在Java7中方法区放在永久代,Java8中方法区放在元空间,并通过GC机制来管理。
  • 虚拟机栈:每个线程私有的空间,由多个栈帧组成,一个方法对应一个栈帧,栈帧包括局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大1M,超出跑出StackOverFlowError。
  • 本地方法栈:类似虚拟机栈,是为虚拟机使用native本地方法而准备的。具体实现由虚拟机厂商来实现。HotSpot虚拟机中实现与虚拟机栈一致,同时超出大小抛StackOverFlowError。
  • 程序计数器:记录当前线程执行字节码的位置,存储的是字节码指令地址,如果native方法,则为空。CPU同一时间只能执行一条线程中的指令,线程切换后通过程序计数器来恢复正确的执行位置。
  • 堆内存:所有线程都可以访问修改,存放的是对象实例,是数据区中占用空间最大的部分,在HotSpot虚拟机中分为新生代和老年代,新生代又分为Eden区和Survivor0区、Survivor1区。
相关文章
相关标签/搜索