JAVA 虚拟机 JVM

JVM 结构

说明: 这里列出几个 jvm 中重要的几个点进行梳理.至于没有涉及到的图中的点,是不需要深入了解的,因为那是涉及 jvm 跟 cpu 之间的交互了,一般都是 c 语言构成的,不在 java 范围内

1.class 文件

class 文件,是由.java文件经过 javac 命令后形成的文件, class 能够被虚拟机识别并运行.

我们看一个.class文件的结构

先看源码Hello.java

public class Hello{
    public static void main(String[] args){
    System.out.print("Hello Java\n");
}}

源码比较简单.

然后看看通过 javac 命令编译之后的文件格式.
这里通过 mac 版的010Editor软件打开的.
直接看图

如图,红框区中的内容就是 class 文件的结构(当然并没有展示完全).

这里再给出一个文件结构的解释图.画的不好,见谅!

好了,关于 class 文件就到这里了.

2.类加载器

1️⃣作用:将 class 文件加载到内存中

2️⃣相关类

ClassLoader LoadPath
Bootstrap ClassLoader JRE\lib\rt.jar 或 Xbootclasspath 选项指定的 jar 包
Extension ClassLoader JRE\lib\ext*.jar 或 Djava.ext.dirs 指定目录下的 jar 包
App ClassLoader CLASSPATH 或 Djava.class.path 指定目录下的类和 jar 包
Custom ClassLoader 通过 java.lang.ClassLoader 的子类自定义加载 class

总结:

1.Bootstrap ClassLoader 和 Extension ClassLoader 是用来加载 jdk特定的 jar 包的.

2.App ClassLoader 是应用程序用到的类加载器

3.Custom ClassLoader 是我们自定义的类加载器,我们可以指定它加载某个目录中的文件(例如在 eclipse 中可以通过动态加载 jar 来扩展相应的功能,就是通过 Custom ClassLoader 来指定要加载的目录的)

3️⃣类的加载机制

双亲加载机制:(委托机制)

这里用一个例子来说明

当我们的类 Hello.class 需要被加载的时候, 也就是说有这样一个类加载的请求的时候,会首先由 App ClassLoader把这个请求交给其父类 Extension ClassLoader 然后 Extension ClassLoader 再把这个请求交给它的父类 Bootstrap ClassLoader .

那么 Bootstrap ClassLoader 会查看 rt.jar 中有没有这个类,也就是有没有被自己加载过.

没有,那么好.

把这个类的加载请求返回给 Extension ClassLoader.同样的 Extension ClassLoader 也会查看一下,这个类有没有被自己加载过.

如果发现被找到了,那么就把Hello.class加载,而 App ClassLoader 就不会再加载这个类了.

如果 Extension ClassLoader 也没有找到这个类,那么这个请求才会被 App ClassLoader 来查看此类是否存在于 classpath 中,存在则加载,不存在则抛ClassNotFoundException异常

以上过程还用用图来总结一下.

以上的内容只是负责把类加载到内存中,那么到内存以后呢?
别急,继续往下看

4️⃣类在内存中

1.loading 就不用说太多了,就是上面我们刚刚介绍的,把.class加载到内存中

2.verifying 负责检查读入的结构是否符合 jvm 规范

3.preparing 分配一个结构来存储类信息.结构中包含了勒种的成员变量,方法和接口信息

4.resolving 把类的常量池中的所有符号引用改变为直接引用

5.initializing 把类中的变量初始化成合适的值,执行静态初始化程序

对以上的步骤了解以后,我们就知道为什么类中的成员变量是先进行的默认初始化,然后才进行的显示初始化了.

3.内存区域

1. 虚拟机栈(Java Stack): 存放 Java 方法执行时的所有数据.每个方法对应一个栈帧,方法的执行就对应着栈帧的入栈到出栈的过程.每个栈帧中包含:局部变量表,栈操作数,动态链接和方法出口.

2. 本地方法栈:类似于 java Stack, 主要用于服务 native 方法

3.方法区:存储类信息,常量,静态变量.并且方法区是永远占据内存的

4.堆 Heap:存储所有通过 new 创建的对象.并且是jvm 中最大的一块内存区域

5.程序计数器保存当前线程执行的内存地址,例如在多线程中,由于可能发生中断而去执行别的线程,所以用来记录当前的执行位置,便于恢复执行

4.垃圾回收机制和相关算法

由于篇幅的问题,这部分内容会用一篇单独的文章来讲解.
主要是垃圾的收集方法垃圾的回收方法
JVM之垃圾回收