最近在学习JVM,顺便写下所学习到的知识,也能加强自己对知识的理解。
直接上图
Java的内存模型主要有五个部分组成,如果更加粗糙的划分,Java的内存模型可以划分成两大类,分别是栈和堆,当然这样划分是不太准确的。由图可以看到Java的内存模型主要由本地方法栈(线程私有),虚拟机栈(线程私有),程序计数器(线程私有),方法区,堆。
本地方法栈与虚拟机栈发挥的作用是十分类似的,不过虚拟机栈是为Java执行方法,本地方法栈是虚拟机为用到的本地方法服务,不管是虚拟机栈还是本地方法栈都会有栈的深度的,要是请求的栈深度比较大,本地方法栈和虚拟机栈都会抛出StackOverFlowError和OutOfMemoryError。
虚拟机栈也是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口信息。每一个方法从调用直到指向完场的过程,就对应一个栈帧在虚拟机栈上个入栈和出栈操作的过程。
程序计数器是一块较小的内存空间,它可以看做是当前线程执行的字节码的行号指示器。在虚拟机的概念模型中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条要执行的字节码服务,分支,循环,跳转,异常处理,线程不回复等基础功能都需要依赖这个计数器来完成。
Java堆是比较的大的一块内存,Java堆是所有线程共享的一块内存,在虚拟机启动的时创建,此内存区域的唯一目的是存放对象实例,,几乎所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此很多时候都被称作“GC堆” ,由于现在收集器基本都采用分代收集算法,所以Java堆中还可以细分为:新生代和老生代;再细分的话有Eden空间,From Survivor空间,To Survivor空间等。现在主流的JVM按照8:1的比例来分配Eden空间和From Survivor空间 ,当然会有两块Survivor空间,两块的Survivor空间是为了GC时轮流的存放依旧有用的对象实例,一块叫From Survivor另一块叫To Survivor 。当GC时虚拟机会把在Eden空间和From Survivor空间中存活的对象复制到另一块干净的To Survivor空间中,然后清理Eden空间和From Survivor 空间,然后From Survivor和To Survivor 互换标记,即From Survivor 变成 To Survivor ,To Survivor变成From Survivor ,下一次GC的时候,虚拟机同样会把在Eden空间和其中一块From Survivor空间中存活的对象复制到另一块干净的To Survivor空间中,然后清理Eden空间和其中一块From Survivor空间。
方法区和Java堆一样,是各个线程共享的 内存区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码等数据。