我们都知道,我们编写的Java程序(.java文件)的运行是通过Java虚拟机完成的,所以对于Java虚拟机的内存结构有一个相对清晰的理解是完全有必要的,这会使我们学习java的过程中更加深刻的认识引用和对象的概念,以及后续学习垃圾回收等其他知识做好铺垫,一下将以比较经典的图片做一个简单介绍,仅供参考。
认识Java虚拟机内存
由上图可以看出,Java虚拟机的内存整体是由栈空间(stack)、堆空间(heap)、程序计数器(PCR)和方法区域构成的。其中栈又分为虚拟机栈和本地方法栈,其中栈和程序计数器是线程私有的,堆空间和方法区域是线程共享的(需要考虑并发数据同步的区域,属于多线程内容),下面我将对每个区域做一个简单介绍。
1.堆空间:
说到堆空间,那当然就和面向对象不可分割了,这个区域存放的数据都是new出来的数据,也就是引用指向的区域,也是实例数据存放的区域,由于是数据共享的,所以是线程不安全的。
2.方法区
在JDK1.8以后,Java虚拟机内存中取消了永久代的概念,方法区是属于堆空间的一部分,和堆空间共享同一块物理地址,但是相关内容实际存放是直接存放在内存中,这样做的好处是空间是可变的,根据不同的内存需要向计算机申请对应的内存。方法区中一般存放的是类加载器(ClassLoader)加载进来(.class)的相关信息,这也是程序为什么可以执行的原因(关于类加载的内容,涉及的内容较多,本文不再一一介绍),值得一说的是类加载的信息都对应一个Class类的实例存放在堆空间中,也就是我们通过反射获得的那个对象。其次,方法区中还保存了可常量常持,以及一些静态数据等等内容。
3.栈空间
Java虚拟机内存中有两个栈空间,一个是虚拟机栈,一个是本地方法栈,两个区域的设计理念都基本相同,都是为了程序执行而存在的,不同是虚拟机栈主要支持Java程序,也就是用户的代码,而本地方法栈的存在是为了支持本地方法(例如finalize()方法等)的实现,由于Java的核心实现涉及c语言或者c++,便有了这个底层技术支持的本地方法栈。
4.程序计数器
程序计数器的作用主要是用于定位每个线程或者程序运行的节点,以实现程序知道自己该从哪里继续执行,这里对比计算机中任务的中断返回有相似之处。
关于栈帧
每一个运行在虚拟机栈的线程,都会被分配一个属于自己的栈帧用于存放当前的缓存数据,通过操作数栈,局部变量表等实现程序的最终功能,一旦执行结束,栈帧会被销毁,这也就是为什么局部变量有作用范围的原因,值得一提的是,栈帧之间可能会有共享区域
这个代表栈帧的增长方向,由指针完成实现,是栈帧之间参数传递的区域。
补充:
关于JDK、JRE、JVM的关系介绍。
JVM + 核心类库 = JRE
运行环境
JRE + Java 开发工具 = JDK
开发环境
名词解释
JVM - Java 虚拟机,Java Virtual Machine
JRE - Java 运行环境,Java Runtime Enviornment
JDK - Java 开发工具包,Java Development Kit
其他
关于执行引擎的了解
JVM的功能实现要配合执行庭引擎的存在,Java执行引擎主要有解释器和即时编译(类似于热点数据)以及GC组成,通过本地方法栈的接口JNI以及本地方法接库,实现了与JVM的交互。