在java中应为不一样的目的能够将java划分为两种内存模型:gc内存模型。并发内存模型。java
java与c++之间有一堵由内存动态分配与垃圾收集技术所围成的“高墙”。墙外面的人想进去,墙里面的人想出来。c++
java在执行java程序的过程当中会把它管理的内存划分若干个不一样功能的数据管理区域。如图:数组
总体上。分为三部分:栈,堆,程序计数器,他们每一部分有其各自的用途;虚拟机栈保存着每一条线程的执行程序调用堆栈;堆保存着类对象、数组的具体信息;程序计数器保存着每一条线程下一次执行指令位置。这三块区域中栈和程序计数器是线程私有的。也就是说每个线程拥有其独立的栈和程序计数器。咱们能够看看具体结构:缓存
在栈中,会为每个线程建立一个栈。线程越多,栈的内存使用越大。对于每个线程栈。当一个方法在线程中执行的时候,会在线程栈中建立一个栈帧(stack frame),用于存放该方法的上下文(局部变量表、操做数栈、方法返回地址等等)。每个方法从调用到执行完毕的过程,就是对应着一个栈帧入栈出栈的过程。并发
本地方法栈与虚拟机栈发挥的做用是相似的,他们之间的区别不过是虚拟机栈为虚拟机执行java(字节码)服务的,而本地方法栈是为虚拟机执行native方法服务的。优化
在hotspot的实现中,方法区就是在堆中称为永久代的堆区域。几乎全部的对象/数组的内存空间都在堆上(有少部分在栈上)。在gc管理中,将虚拟机堆分为永久代、老年代、新生代。经过名字咱们能够知道一个对象新建通常在新生代。通过几轮的gc。还存活的对象会被移到老年代。永久代用来保存类信息、代码段等几乎不会变的数据。堆中的全部数据是线程共享的。spa
新生代:应为gc具体实现的优化的缘由。hotspot又将新生代划分为一个eden区和两个survivor区。每一次新生代gc时候。只用到一个eden区,一个survivor区。新生代通常的gc策略为mark-copy。操作系统
老年代:当新生代中的对象通过若干轮gc后还存活/或survisor在gc内存不够的时候。会把当前对象移动到老年代。老年代通常gc策略为mark-compact。线程
永久代:永久代通常能够不参与gc。应为其中保存的是一些代码/常量数据/类信息。在永久代gc。清楚的是类信息以及常量池。对象
如同其名称同样。程序计数器用于记录某个线程下次执行指令位置。程序计数器也是线程私有的。
java试图定义一个Java内存模型(java memory model jmm)来屏蔽掉各类硬件/操做系统的内存访问差别,以实现让java程序在各个平台下都能达到一致的内存访问效果。java内存模型主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。模型图以下:
java内存模型中规定了全部变量都存贮到主内存(如虚拟机物理内存中的一部分)中。每个线程都有一个本身的工做内存(如cpu中的高速缓存)。线程中的工做内存保存了该线程使用到的变量的主内存的副本拷贝。线程对变量的全部操做(读取、赋值等)必须在该线程的工做内存中进行。不一样线程之间没法直接访问对方工做内存中变量。线程间变量的值传递均须要经过主内存来完成。
关于主内存与工做内存之间的交互协议,即一个变量如何从主内存拷贝到工做内存。如何从工做内存同步到主内存中的实现细节。java内存模型定义了8种操做来完成。这8种操做每一种都是原子操做。8种操做以下:
lock(锁定):做用于主内存,它把一个变量标记为一条线程独占状态;
unlock(解锁):做用于主内存,它将一个处于锁定状态的变量释放出来,释放后的变量才可以被其余线程锁定;
read(读取):做用于主内存,它把变量值从主内存传送到线程的工做内存中,以便随后的load动做使用;
load(载入):做用于工做内存,它把read操做的值放入工做内存中的变量副本中;
use(使用):做用于工做内存,它把工做内存中的值传递给执行引擎,每当虚拟机遇到一个须要使用这个变量的指令时候,将会执行这个动做;
assign(赋值):做用于工做内存,它把从执行引擎获取的值赋值给工做内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操做;
store(存储):做用于工做内存,它把工做内存中的一个变量传送给主内存中,以备随后的write操做使用;
write(写入):做用于主内存,它把store传送值放到主内存中的变量中。