JVM简述(面试之前看一遍)
上图,我们从上往下一一解析:
类装载器(ClassLoader)
类装载器负责加载由.java 文件生成的.class文件。
class文件在文件的开头有特定的文件标识,将class文件字节码加载进内存中,并将这些内容转换成方法区中的运行时数据结构。ClassLoader只会负责class文件的加载,至于它是否可以运行,则由其他模块决定
ClassLoader类装载器有4个
- 启动类加载器 Bootstrap, 加载JDK自带的class文件 如Object类
- 扩展类加载器 Extension, 加载扩展包中的类
- 应用程序加载器 AppClassLoader, 加载我们自己写的类
- 自定义加载器(不重要,不管)
类加载器有一个继承关系,顶级父类是Bootstrap加载器,Extension继承了Bootstrap,AppClassLoader再继承Extension。
双亲委派机制
每一个类,在加载的时候,都会由当前的类加载器往上找,找到父类加载器。最后会找到Bootstrap顶级加载器。Bootstrap处理不了,再传给子类加载器处理
比如我现在自己编写了一个类a.java。
- AppClassLoader拿到了,让Extension处理
- Extension拿到了,让Bootstrap处理。
- Bootstrap处理不了,让Extension处理。
- Extension处理不了,让AppClassLoader处理。
双亲委派机制的意义:避免我们编码期间,写了一个类比如java.lang.String。这个类是系统自带的类,但我们自己编码不规范,完全重名了。如果不抛给顶级Bootstrap去发现这个问题,程序启动成功。那现在java.lang.String就会存在两个。我到底用拿一个呢?(保证我们的代码不能污染java的源代码)
本地方法接口、本地方法栈(了解)
- 本地方法接口:融合不同计算机语言为JAVA所用。比如我们JDK中的一些native修饰的方法。
- 本地方法栈:登记所有native方法。
程序计数器(PC寄存器)
cpu有一块空间叫PC寄存器:简单一句话,就是一个指针。
每个线程都有一个PC寄存器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用于储存向下一条指令的地址,以就是将要执行的代码),由执行引擎读取下一条指令,是一个非常小的内存空间。
方法区(比较重要)
方法区所有线程共享。
首先明确一点,叫方法区,但它绝对不是放方法的地方!!!
方法区:存储每一个类的结构信息,什么是结构信息?Class对象明白吗?没错,就是存每个类的Class对象(类模板对象的字节码文件)。
方法区只是一个规范,在不同版本的JVM中有不同的实现方式,最典型的就是永久代和元空间。
什么意思呢?
可以理解为:方法区是一个接口,定义了基本的规范,永久代和元空间是对方法区不同的实现。
方法区大小的设置
方法区的内部结构(经典结构)
类型信息:
域(Field)信息/或叫变量信息:
方法(Method)信息:
运行时常量池 VS 常量池:
常量池
为什么需要常量池呢?
常量池中有什么呢?
运行时常量池
JDK1.8后方法区的内部结构(现有结构)
方法区的垃圾回收
栈(非常重要)
栈空间每个线程单独持有。
总体概述:栈管运行,堆管存储。
栈,也叫栈内存,主管java程序的运行,是在线程创建的时候创建,线程结束占栈也就释放。对于栈来说不存在GC垃圾回收的问题。8中基本类型的变量和对象的引用变量以及实例方法都是在栈内存中存贮。
宏观上来说,栈主要保存:
- 栈操作:记录出栈入栈的操作
- 栈帧(就是一个Java方法)数据:包括类文件,方法等等。
栈帧
栈里所有数据都是以一个一个栈帧的形式存在的,一个方法对应一个栈帧!
1.局部变量表
2.操作数栈
3.动态链接
4.方法返回地址
栈、堆、方法区的关系
堆(非常重要)
链接: JVM中堆空间简述,JVM调优以及GC垃圾回收算法.
好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。