首先JVM在Java体系中是最最最最最最底层的
其次它有两个概念
JDK 可以理解为Java开发使用最小的工具(JDK里面包含了JRE)
JRE 可以理解为运行Java程序的标准环境
为什么说java“一次编写,到处运行” 其实就是因为虚拟机,跟你的平台无关,只要你有JJVM,程序就能跑得动
先学习以下JVM的结构(可以顺便学习以下计算机组成原理与体系结构)
1.堆和栈(两个概念)
简单来说 堆存放对象 ,栈存放执行的程序
2.运行时的数据区域
线程独有的内存区域
程序计数器:线程独有(想一想就知道了,每个线程都需要独立的程序计数器,用来指示下一条要执行的指令位置,如果不独有,那程序执行不就乱了码),存储下一条指令的地址
虚拟机栈:生命周期和线程相同,用于存储局部变量表,方法出口。方法的执行就是入栈和出栈的过程
局部变量表:存放函数的参数以及局部的变量信息,变量作用域是当前调用的函数
本地方法栈:为JVM使用本地方法来服务
线程共享的内存区域
堆:存放对象实例
方法区:虚拟机加载的类信息、常量、静态变量、编译器编译后的代码
涉及类加载器:分为启动类加载器,扩展类加载器,应用程序类加载器(又可以自定义类加载器)
启动类加载器:可以指定父类加载器,加载扩展类,应用程序类加载器,加载核心库
扩展类加载器:加载扩展库
应用程序类加载器:加载应用程序类
自定义:实现自己的类加载器
运行时常量池:存放编译时生成的各种字面量和符号引用,还有编译出来直接引用
JVM加载顺序
假设new一个对象,首先检查能不能找到这个类的引用(运行时常量池中查找),其次看这个类是否已经加载、解析、初始化,如果没有,则执行这些过程
再下来就是给这个对象分配内存,有两种分配方法 指针碰撞法(用指针分割内存,一边是使用过的,一边是未使用的),又或者维护一个表,上边记录了所有的空闲区域
初始化内存为0,对象头不为0(这也是为什么我们定义一个变量不赋值,但在执行的时候默认值为0,JVM帮我们干了)
在对象头中放入一些必要信息,比如这个对象是那一个类的实例
然后执行init
对象建好之后,剩下的就是如何去找到它,通过栈的reference引用,就像Student stu = new Student() 其中 stu就是引用,有两种方式,句柄和指针来让stu访问对象
句柄访问就是 建立一个句柄池,里面放着对象的句柄,包括了类信息,实例信息,引用指向的是对象句柄的地址(个人理解 更像是间接访问)
指针访问 引用直接指向对象,对象里面存放类信息,实例信息(更像是直接访问)