从执行class文件开始认识JVM

编写好的java文件经过javac编译成class文件,使用java命令执行对应得我class文件,这时候jvm开始运行
首先,jvm需要将class文件装载进入内存空间(类加载机制)
在内存中分配空间(认识JVM运行时数据区)

类加载机制

类加载分为几个步骤

  1. 装载

class文件装载进JVM首先要进行的就是要将对应的字节码数据装载进内存空间,需要知道字节码文件地址,装载到内存中哪个区域,怎么使用这些数据?这里牵出装载阶段主要做的3件事

通过全类名获取定义类的二进制字节流
将字节码对应的静态数据结构转换成方法区的运行时数据结构
在堆中生成class对象,当做这些数据的访问入口

  1. 连接

连接阶段有三个步骤:验证、准备、解析
**验证 **-> 验证字节码文件的准确性,安全性等,防止威胁到虚拟机的安全
**准备 **-> 正式为类变量(静态变量)分配内存空间并附默认值(比如int默认值为0)

这里需要注意jdk1.7和之前,类变量在方法区中分配空间
jdk1.8之后,字符串常量池和静态变量移动到堆中分配空间

解析 -> 将符号引用转换成直接引用

通俗理解就是将class文件中的那些表示不同类型或者值的符号转换成内存空间中的地址

  1. 初始化

初始化阶段是执行方法,该方法在编译后自动生成,用于给静态变量赋值等

JVM中的内存区域

上面已经提到过方法区和堆,大致知道以下两点:

  1. 方法区 由线程共享 主要存储加载到虚拟机中的类信息,字段信息,方法信息,常量,静态变量以及即时编译器编译后的代码缓存等

方法区只是一个概念
JDK1.7和之前使用永久代实现方法区
JDK1.8之后使用Meta Space元空间实现方法区,并且不再在JVM的运行时数据区,而是直接使用本机内存

  1. 堆 由线程共享,主要存储几乎所有的对象信息

认识到以上几点以后,开始考虑,现在class文件已经加载进入JVM的内存空间中,那么方法执行过程中需要做什么,对应的需要哪些内存区域?

  1. 虚拟机栈 线程独享,每调用一个方法压入一个栈帧,栈帧中保存着局部变量表,操作数栈、动态链接、方法返回地址等信息,每执行完一个方法就会弹出相应的栈帧
  2. 程序计数器 现成独享,因为CPU的高速轮换需要在切换线程时记录当前线程执行的位置等信息
  3. 本地方法栈 作用和虚拟机栈相同,虚拟机栈用于执行Java方法,本地方法栈用于执行native方法

双亲委派模型

类加载过程中的第一步,装载class字节码文件,需要用到类加载器,虚拟机中的类加载器分为三个:
根加载器(启动类加载器)
扩展类加载器
应用类加载器
三个加载器各自负责加载的位置不同,并且他们通过持有上一级加载器对象实现组合关系
在loadClass方法中,
首先检查自己是否加载过,如果没有加载过,调用组合关系中的上一级来加载
当上一级发现自己也没有加载过,继续调用自己的上一级来加载,直到上一级为空,说明当前是根加载器
然后根加载器就会开始尝试从自己负责的范围开始加载,找不到就返回null
当下一级接收到的对象为null时,开始尝试从自己负责的范围开始加载,同样找不到就返回null
直到最终的应用类加载器或者自定义加载器
想要破坏双亲委派模型需要重写loadClass方法

你可能感兴趣的:(jvm)