Java内存模型(Java升级计划1)

Java内存模型

JVM什么时候启动

类被调用的时候
启动JVM线程,再启动其他的线程,包括main线程,也就是JVM线程创建了其他的线程。

线程在JVM中是怎么运行的


方法区:存放的是一些加载的类信息(类加载器加载classload),常量,static变量,JIT编译后的代码。,也可以出现out of memory

JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意广义与狭义的JIT编译所指的区别。

Java堆区:大量的实例对象,也可以出现out of memory

方法区和堆区可以实现信息共享
VIM Stack:Java在运行时的内存模型,数据私有,不能实现数据共享

每一个方法有唯一的栈帧去对应去存放数据

当栈帧放满了VIM Stack时,任然不断的添加,就会出现内存溢出,也可以出现out of memory

程序计数器(PC):Java线程的私有数据,这个数据就是执行下一条指令的地址,也就是说当这条指令执行完成之后,通过程序计数器指向下一条指令的地址
Native method stack(本地方法栈):虚拟机的native方法有关

既然在内存中划分出了这样的5个区域,那么在物理内存中是否也划分出这样的5个区域呢?

在虚拟机中划分出的这种区域,其实在Java的内存中并没有这样的内存划分,在计算机的内存中只有主从

Java内存模型 Java memory model

Java内存模型指的是一种规范。是一种抽象的模型,是不存在的。
作用:指导和规范我们的数据交互。

每一个线程都有私有的工作空间

当线程需要访问一个数据的时候,在工作空间寻找,发现没有,把内存中的数据复制到工作空间中,然后在工作空间中进行修改,再把修改后的值刷新到主内存中
主内存:存放的是一些共享的信息
工作内存:私有信息,基本数据类型,直接分配到工作内存,引用的地址存放在工作内存,引用的对象存放在堆中
工作方式

  • 线程修改私有数据,直接在工作工作空间修改
  • 线程修改共享数据,把数据复制到工作空间,先在工作空间修改,修改完成以后,然后刷新到主内存中

JVM和JMM的联系
首先JMM是一种抽象概念,是不存在的,而JVM就是按照JMM的规范去实现的结果

硬件内存架构与Java内存模型之间的关系

为什么要这么设计呢?

因为CPU的执行速度很快,但是内存的读写跟不上CPU的执行速度,所以使用了缓存的策略来设计。
缓存有一级缓存,二级缓存,甚至到三级缓存,缓存的容量比内存小但是读写速度比内存高。
缓存越低,存储的容量越小,但是速度越贴近CPU的处理速度,但是CPU不是直接访问cache的数据的,CPU中存在一个寄存器,每一个CPU都有寄存器,有寄存器存储数据,如果寄存器中没有找到对应的数据再去缓存中进行查询。

CPU缓存的一致性问题:并发处理的不同步

解决方案

  • 总线加锁(BUS): 降低了CPU的吞吐量
  • 缓存一致性协议:Intel中的MESI协议

MESI协议:当CPU在cache中操作数据时,如果该数据是共享变量,数据在cache中读到寄存器中,进行新的修改,并更新内存数据,Cache LINE置无效,当其他CPU发现cache LINE无效的时候,就从内存中读取数据

Java内存模型与硬件内存架构的关系

数据交叉关系:会导致数据的不一致。

Java线程最终是要在CPU中运行的,它运行的方式是什么样的呢?

JMM的必要性

规范内存数据和工作空间的数据交互

并发编程的三个重要特性

  • 原子性:不可分割,比如x=1,这样一个赋值的过程就是原子性的
  • 可见性:线程对于自己的工作空间对于其他的线程是不可见的,只能操作自己工作空间的数据
  • 有序性:程序中的顺序不一定就是代码执行的属性。因为代码在编译时会有一个编译重排序,和指令重排序,目的时为了提交程序的运行效率。

重排的原则as-if-seria,这个重排的原则针对的是单线程的,在单线程中,重排后不影响执行的结果。和指令操作的时间有关系
如果是多线程的话,那么就是happens-before规则

关于这个重排,在编译的时候重排是代码优化,而指令重排是运行优化

JMM对三个特征的保证

  • 1.JMM与原子性
    X=10 这只是一个写操作,所以这具有原子性,如果是私有数据具有原子性,如果是共享数据没原子性
    y=x 这个是没有原子性的,因为这个分为两个步骤,把X读到工作空间(原子性),然后把X的值写到Y(原子性)。两个具有原子性的操作放在一起不具有原子性。
    i++ 没有原子性,步骤分为把 i 读到工作空间,+1,然后刷新结果到内存
    z=z+1 没有原子性

多个原子性的操作合并到一起就没有原子性

怎么才能让多个原子性的操作任然保持原子性呢?
Synchronized
JUC Lock的lock

  • 2.JMM与可见性
    Volatile:用volatile关键词的时候,是在JMM的基础上模拟了CPU的MESI协议
    Synchronized:加锁
    JUC 中的Lock的lock
  • 3.JMM与有序性
    Volatile
    Synchronized

Happens-before原则:

  • 程序次序原则,就是在程序进行编译重排和指令重排的时候,对程序运行的结果是不能变的
  • 锁定原则:后一次加锁必须要等前一次解锁
  • volatile原则:只要前面加了volatile修饰的变量,那么这个变量的顺序在重排时期不允许去变
  • 传递原则:
语句A
语句B
语句C

那么意味着语句A必须在语句C前面进行执行

# Java  JVM 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×