虚拟机
所谓虚拟机就是一台虚拟的计算机,他是一块软件,用来执行一系列虚拟计算机指令,大体上,虚拟机可以分为系统虚拟机和程序虚拟机
Vmware,Visual Box都是系统虚拟机,他们完全是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台
程序虚拟机就是java虚拟机,专门为执行单个计算机程序而设计,在java虚拟机中执行的指令我们称为java字节码指令
无论徐通虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中
java虚拟机
是一台执行java字节码的虚拟计算机,他拥有独立的运行机制,运行的java字节码也未必有java语言编译而成
jvm平台的各种语言可以共享java虚拟机带来的跨平台性,优秀的垃圾回收器,以及可靠的即使编译器
java技术的核心就是java虚拟机,因为所有的java程序都循行在java虚拟机内部
特点:
-
一次编译,到处运行
-
自动内存管理
-
自动垃圾回收
JVM的位置
JVM整体结构
类文件——类装载器子系统——运行时数据区——执行引擎——本地方法接口
Hotspot VM是目前市面上高性能虚拟机的代表作之一
他采用解释器与即时编译器并存的架构
java代码执行流程
JVM的架构模型
java编译器输入的指令两种
-
栈的指令集架构
-
寄存器的指令集架构
JVM的生命周期
-
虚拟机的启动
java虚拟机的启动是通过引导加载器创建一个初始类来完成的,这个类是有虚拟机的具体实现指定的
-
虚拟机的执行
-
一个运行中的java虚拟机有着一个清晰的任务:执行java程序
-
程序开始执行是他才运行,程序结束时他就停止
-
执行一个所谓的java程序是,真正在执行的是一个java虚拟机的进程
-
-
虚拟机的退出
-
程序正常执行结束
-
程序在执行过程中遇到了异常
-
操作系统中出现错误遇到了异常或者错误而异常终止
-
线程调用runtime类或者system类的exit方法,或者runtime类的halt方法
-
类加载器子系统
类加载器子系统的作用
类加载子系统负责从问价徐通或者网路中加载class文件,class文件在文件开头有特定的文件表示
classloader只负责class文件的加载,是否可以运行,则有executionEngine决定的
加载的类信息存放于一块称为方法区的内存空间,除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量的数字常量
类的加载过程
加载:
-
通过一个类的全限定名获取定义类的二进制字节流
-
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
-
在内存中生成这个类的java。lang。class对象,作为方法区这个类的各种数据的访问入口
链接:
-
验证
确保class文件的字节流中包含的信息符合当前虚拟机要求,保证被加载类的正确性
-
准备
为类变量分配内存并且设置该类的默认初始量
-
解析
将常量池内的符号引用转换为直接引用的过程
主要针对类或者接口,字段方法等
初始化
就是执行类构造器方法的过程
类加载器的分类
JVM支持两种类型的类加载器,分别为引导类加载器(以java,javax,sun开头呢)(c,c++实现的,嵌套在jvm内部)和自定义类加载器(继承classloader)。
自定义加载器又分为系统加载器和扩展加载器(jer,
java的核心类库都是使用引导类加载器进行加载的。比较高端,
classloader的方法
获取classloader的途径
双亲委派机制
java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类是才会将他的class文件加载到内存生成class对象,而且加载某个class文件时,java虚拟机采用的时双亲委派模式,即把请求交由父类处理,他是一种任务委派模式
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载还存在其父类加载器,则进一步向上委托,依次往上,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,如果父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
优势:
通过层级关系可以避免类的重复加载,
也可以保护程序的安全,防止核心API库被随意串改
沙箱安全机制
保护java核心源代码的被任意篡改,就是沙箱安全机制
两个class对象是否时同一个类
在jvm表示两个class对象是否时同一个类,存在两个必要条件
-
类的完整类名必要一样,包括包名
-
加载这个类的classloder必要也是同一个
运行时数据区
内存时非常重要的系统资源, 时硬盘和cpu的中间仓库及桥梁,承载着操作系统和应用程序的实时运行,jvm内存布局规定了java在运行过程中内存申请。分配,管理,的策略,保证了jvm的高效稳定运行,不同的jvm对于内存的划分和管理机制存在部分差异。
方法区和堆时一个进程一份
程序计数器,本地方法栈,虚拟机栈是一个线程一个
程序计数器(pc计数器)
寄存器存储指令相关的现场信息,cpu只有把数据装在到寄存器才能运行
JVM中的pc寄存器是对物理pc寄存器的之中抽象模拟
每一个线程都一个程序计数器
pc寄存器是用来存储只想下一条指令的地址,也即将要执行的指令代码,由执行引擎读取下一条指令
pc寄存器存储地址由什么用的
因为cpu需要不停的切换各个线程,这个时候,就要知道从哪里开始
pc寄存器为什么会被设定为私有
为了能够准确记录各个线程正在执行的当前字节码指令地址,最好的办法自然是为每一个线程都分配一个pc寄存器
栈
每个线程都有自己的栈,数据都是以栈帧的格式存储的
每个方法都各自对应一个栈帧
栈帧是一个内存区块,是一个数据集,联系着方法执行过程中的各种数据信息
栈帧主要分为:
-
局部变量
-
方法返回地址
-
操作数栈
-
动态链接
-
一些附加信息
本地方法栈
native关键字修饰的
与java环境交互
与操作系统交互
sun‘s的交互
堆
几乎所有的对象实例都在堆中
方法结束后,GC执行垃圾回收的重点区域
方法区
方法区是各个线程贡献的内存区域
方法区的大小空间可以固定和扩展
如果系统定义太多的类,导致方法区一处,会抛出异常
面试题
垃圾回收
垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾