JVM内存模型详解
图解
JVM内存模型主要由运行时数据区、类加载子系统、执行引擎组成。
类加载子系统将硬盘上的.class文件加载到运行时数据区,由执行引擎来执行刚刚加载的数据。这就是jvm运行java运行程序的一个基础。
程序计数器
程序计数器:
- 程序计数器是指虚拟机字节码指令的地址,它是一块很小的内存空间,也是运行速度最快的存储区域。
那么jvm内存模型中为什么需要程序计数器呢?
- 因为处理器要执行的程序都是以二进制代码序列方式预存储在计算机的存储器中,处理器将这些代码逐条地抽取到处理器中再译码、执行,用以完成整个程序的执行。为了保证程序能够持续的执行下去,CPU就必须具有某些手段来确定下一条取指指令的地址,所以就需要程序计数器了,通常又称之为指令计数器。
由于java是支持多线程的语言,即在多线程环境下,为了让线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各计数器之间互不影响、独立存储,因此这块内存是线程私有的。
虚拟机栈
-
虚拟机栈用来存放局部变量、方法出口、动态链接、操作数栈,用来解决程序运行的问题,就是说如何执行的这个方法,如何处理数据。
-
虚拟机栈在运行时使用一种叫做栈帧的数据结构保存上下文数据,栈帧中就存放了局部变量、方法出口、动态链接、操作数栈和f返回地址等信息,每一个方法的调用都伴随着栈帧的入栈操作,相应地,方法的返回则表示栈帧的出栈操作。
-
栈帧由三部分组成,即局部变量区( ocal Variables )、操作数栈( Operand Stack )和帧数据区(Frame Data )。
本地方法栈
- 本地方法找(Native Method Stacks )和 Java 虚拟机栈的功能很相似, Java 虚拟机栈用于管理Java 函数的调用,而本地方法栈用于管理本地方法(native修饰的方法)的调用。本地方法并不是用 Java 实现的,而是使用 C语言实现的。
- 当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界,本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区,但不止于此,它还可以做任何它想做的事情。
- 本地方法本质上是依赖于实现的,虚拟机实现的设计者可以自由地决定使用怎样的机制来让Java 程序调用本地方法,任何本地方法接口都会使用某种本地方法栈。
堆
- 堆是由垃圾回收机制来负责的,堆的优势就是可以动态分配内存大小,生存周期也不需要事先告诉编译器。由于它是在运行时动态分配内存的, Java 的垃圾收集器会自动收走那些不再使用的数据。但是缺点是,由于要在运行时动态分配内存,所以数据访问速度较慢。大多数的虚拟机里 Java 中的对象和数组都存放在堆中。
- 堆中主要存放new出来的对象和数组,堆呢主要分为老年代和新生代区。
- 对象的创建就是在新生代区的eden中,经过一个Mintor GC后,还存在的话,进入到Survivor区,此时会有一个默认的年龄Age=1,每经过一次Mintor GC后,还存在的话,age加一,直到阈值的时候,就会进入到老年代。阈值默认是15,不过可以自己调的。
方法区(元空间)
- 方法区主要保存的信息是类信息、静态变量、即时编译器编译后的代码。
- 方法区中最重要的是类的类信息、常量池、域信息、方法信息。