JAVA类加载器:
一个java文件从编译完成到最终执行,一般经过两个过程:编译和运行;
- 编译:即把写好的java文件,通过javac命令编译成字节码,也就是常说的.class文件。(编译器)
- 运行:则是把编译生成的.calss文件交给java虚拟机运行。(类加载器)
而我们常说的类加载过程就是指java虚拟机把.class文件加载到内存中,并进行解析生成对象的过程。
例子:java虚拟机执行到某段代码的时候,遇到calssA,然而内存中并没有classA,java虚拟机就会去寻找classA,并将其加载到内存中。
类什么时候被初始化:
- 创建实例的时候(new 对象)
- 访问某个类的静态变量或调用静态方法;
- 反射,初始化一个类的子类,会先初始化父类;
- jvm启动的时候标明的启动类;
JVM中编译器:
xxxx
JVM中包括几种类加载器:
- 引导类加载器:BootStrapClassLoader
- 扩展类加载器:ExtClassLoader
- 应用类加载器:AppClassLoader
- 用户自定义类加载器:CustomClassLoader
JAVA类加载过程(先类加载才能初始化)
- 加载
- 链接:2.1 验证 2.2 准备 2.3 解析
- 初始化
加载:指的是把class字节码文件加载到内存的过程;
验证:主要为了保证加载进来的字节流符合虚拟机的规范,不会造成错误。
如:文件格式验证;类的字段是否和父类冲突;是否有不合理的重载;常量是否是支持的等等;
准备:主要为了类变量分配内存,并且赋予初始值;
备注:不是代码中写的初始值,而是java虚拟机根据不同的变量类型的默认初始值;
解析:将常量池内的符号引用替换为直接引用的过程;
如:现在调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。
在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。
初始化:主要对类的变量初始化,是执行类构造器的过程。换句话说,只对static修饰的变量或语句初始化;如果初始化一个类,其父类还未初始化,则优先初始化其父类;如果同时包含多个静态变量,则自上而下执行;
(后面还有使用和销毁、垃圾回收,才是整个类的生命周期)
类初始化的过程(顺序)
- 如果有父类先去初始化顶级父类(obj-爷爷--父亲-自己)
- 静态变量初始化;静态代码块初始化;构造器初始化;
JVM的内存的结构
在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理。
JVM的内存模型
Java虚拟机大致分为:Stack、Heap、方法区三个主要部分:
1:方法区:静态分配的,又叫静态区。编译器将变量绑定到某个存储位上,而且这些绑定不会在运行的时候改变(编译时确定),是所有线程共享的。
2:栈:是一个逻辑概念,特点是先进先出。一个栈的空间可能是连续或不连续。最典型的是栈应用场景,java虚拟机每次调用一次方法就创建一个方法帧,退出方法则对应方法帧被弹出。栈中存储的数据也是运行时候确定的。
3、堆:在运行时进行存储空间分配和收回的内存管理模型(运行时确定)。Java 对象的内存总是在 heap 中分配。