jvm(Java虚拟机)先来个图示
jvm由类加载器、运行时数据区、执行引擎、本地库接口组成。
java中类加载机制是双亲委派模式,子类先委托父类加载,父类加载器有自己的加载范围,范围内没有找到,则不加载,并返回给子类,子类在收到父类无法加载的时候,才会自己去加载。双亲委派的好处,保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。
加载器有:
- 启动类加载器(Bootstrap ClassLoader):C++实现,在java里无法获取,负责加载/lib下的类。
- 扩展类加载器(Extension ClassLoader): Java实现,可以在java里获取,负责加载/lib/ext下的类。
- 应用程序类加载器(Application ClassLoader):我们写的代码默认就是由它来加载,ClassLoader.getSystemClassLoader返回的就是它。
- 自定义类加载器
加载阶段有:
- 加载:讲二进制字节流的存储结构转化为特定的数据结构存储在内存
- 检查:验证二进制字节流中信息是否符合虚拟机规范,有没有安全问题
- 准备:静态变量分配内存空间
- 解析:常量池中的符号引用替换为直接引用的过程,检查指定的类是否引用了其他的类
- 初始化:赋值
其中检查、准备、解析三个也叫链接,就变成加载、链接、初始化。
运行时数据区:
一、堆:
- 存储的全部是对象,每个对象包含一个与之对应的class信息–class的目的是得到操作指令。
- jvm只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身。
- 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。
- 缺点是,由于要在运行时动态分配内存,存取速度较慢。
二、栈:
- 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。对象都存放在堆区中。
- 每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
- 栈分为3个部分:基本类型变量,执行环境上下文,操作指令区(存放操作指令).
- 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。
- 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
三、方法区:
方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
四、本地方法栈:
一个支持native方法调用的JVM实现,需要有这样一个数据区,就是本地方法栈,Java官方对于本地方法的定义为methods written in a language other than the Java programming language,就是使用非Java语言实现的方法,但是通常我们指的一般为C或者C++,因此这个栈也有着C栈这一称号。
五、程序计数器:
程序计数器用来记录当前正在执行的指令,在JVM中也是如此。程序计数器是线程私有,所以当一个新的线程创建时,程序计数器也会创建。由于Java是支持多线程,Java中的程序计数器用来记录当前线程中正在执行的指令。
原创文章,作者:LeeC,如若转载,请注明出处:https://digoak.com/technology/java/03/java-jvm%e7%bb%93%e6%9e%84%e8%a7%a3%e6%9e%90/