首先要区分java内存区域与java内存模型(JMM)
java内存区域:是指在java程序运行时JVM对物理内存的划分。
java内存模型:是一组规则JMM,包括原子性,有序性,可见性,将物理内存抽象划分为主内存与工作内存。这组规则是虚拟机JVM为了处理线程安全问题而制定。
java虚拟机直接操作的对象为线程。
java的内存区域分为:
线程共享区域:堆内存,方法区
线程私有区域:本地方法栈,虚拟机栈,程序计数器
1.堆内存:在虚拟机启动时创建,是垃圾回收GC操作的主要区域,存储所有的对象实例,当堆内存无法再**做垃圾回收,且无法扩展时会抛出OutOfMemoryError 异常,也就是内存溢出。
2.方法区:属于线程的共享区域,也就是除了对象,编译器编译后(虚拟机加载类后)的所有共享数据都存在方法区里面,例如:常量,静态变量,类信息等。方法区还存在一个运行时常量池,它主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用,例如:String s = “11”;int a = 1;
3.虚拟机栈:线程的私有区域,在线程创建时创建,用于存储线程方法调用的栈,每一个栈帧对应线程调用的一个方法,栈帧存储了改方法的变量表、操作数栈、动态链接方法、返回值、返回地址等信息。每个方法从调用直结束就对于一个栈桢在虚拟机栈中的入栈和出栈过程。
4.程序计数器:属于线程私有的数据区域,是一小块内存空间,主要代表当前线程所执行的字节码行号指示器。字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
5.本地方法栈:本地方法栈属于线程私有的数据区域,这部分主要与虚拟机用到的 Native 方法相关,一般情况下,我们无需关心此区域。
java内存模型:
JMM与Java内存区域的划分是不同的概念层次,更恰当说JMM描述的是一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式,JMM是围绕原子性,有序性、可见性展开的。
JMM将java内存抽象为主存与工作内存,对应着内存区域中的共享区域与私有区域。
1.主存:存储所有的共享数据,可以理解为堆内存与方法区的合并,不同的无论成员变量还是本地变量(局部)都存储在主存中。
2.工作内存:包括线程私有的数据,工作内存中的变量为主存中变量的副本,线程只能修改自己工作内存中的变量,在覆盖到主存中,而 多个线程同时进行这个操作往往会产生线程安全问题。
JMM通过制定一组访问主存与工作内存的规则,来保证三个特性,从而解决线程安全问题,括号内为解决方式:
1.原子性:每一个操作都是原子类型的,无法继续拆分的。(synchronized,重入锁)
2.可见性:线程对变量做得操作,对其他线程来说都是可见的,其他线程能够获取到新的变量内容。(synchronized,volatile)
3.有序性:消除因为指令重排导致的线程操作乱序问题。(volatile)
happens-before 原则可解决三个特性。
网友评论