# jvm笔记

jvm运行在操作系统上,它与硬件没有直接交互。

java中负责对字节代码解释执行的是虚拟机。

体系结构:

JVM

# 类加载器/Class Loader

负责加载class文件,class文件在文件开头有特定的文件标示。并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。

ClassLoader

# 虚拟机自带的加载器

  • 启动类加载器:BootstrapClassLoader (cpp实现)
  • 平台类加载器:PlatformClassLoader (java实现)
  • 应用类加载器:AppClassLoader (java实现,也叫做“系统类加载器”)

启动类加载器,负责加载JVM虚拟机运行时所需的基本系统级别的类,如java.lang.String, java.lang.Object等等。启动类加载器无法通过any.javaClass.classLoader的方式取得。(因为它不是java实现的)

平台类加载器之前叫Extension Class Loader,但是java 9 之后为了支持模块系统,扩展机制被删除。

在java 9 之后,运行下列代码:

class MyClass

fun main() {
    val myClass=MyClass()
    println(myClass.javaClass.classLoader)
    println(myClass.javaClass.classLoader.parent)
    println(myClass.javaClass.classLoader.parent.parent)
}

会打印:

jdk.internal.loader.ClassLoaders$AppClassLoader@42a57993
jdk.internal.loader.ClassLoaders$PlatformClassLoader@eed1f14
null

# 双亲委派

双亲委派模型工作过程:一个类加载器收到类加载的请求,它首先会把这个请求委派给父类加载器去完成,层层上升,只有当父类加载器无法完成此加载请求时,子加载器才会尝试自己去加载。

要注意的是父加载器和子加载器的关系不是继承关系而是组合关系。子加载器中有一个私有属性 parent 指向父加载器。

# 沙箱机制

沙箱安全机制是由基于双亲委派机制上,采取的一种JVM的自我保护机制,假设自己写一个java.lang.String 的类,在类中自定义方法,由于双亲委派机制的原理,此请求会先交给Bootstrap试图进行加载,但是Bootstrap在加载类时首先通过包和类名查找rt.jar中有没有该类,有则优先加载rt.jar包中的类,没有自定义方法会报错,因此就保证了java的运行机制不会被破坏。

# 用户自定义的加载器

java.lang.ClassLoader的子类,用户可以自定义类的加载方式。

# 执行引擎 / Execution Engine

Execution Engine负责解释命令,提交给操作系统执行。

# 本地接口 / java native interface / JNI

用于调用c/cpp方法

# 本地方法栈 / Native Method Stack

Native Method Stack中登记native method,Execution Engine执行时加载本地方法库。

# 程序计数寄存器 / Program Counter Register

每个线程都有一个程序计数器。是线程私有的,就是一个指针,指向方法区的方法字节码(用来存储指向下一条指令的地址),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。

# 方法区 / Method Area

方法区被所有线程共享,所有字段和方法字节码,以及一些特定的方法如构造函数,接口也在此定义。所有定义的方法的信息都保存在该区域,此区属于共享空间

静态变量+常量+类信息(构造方法/接口定义)+运行时常量池存在方法区中。

但是实例变量存在堆内存中,和方法区无关。