
类加载器:搬运工,将字节码文件加载到内存中
是JVM中的核心系统,
职责:
把字节码文件加载到内存(JVM的方法区中),并在堆区生成一个对应的java.lang.Class对象
如果没有这个,所写的.java源码即使被编译成字节码,对JVM来说也无法运行
JVM中默认有以下四种类加载器
启动类加载器(BootStrap ClassLoader)
- 地位: 最顶层的加载器,由C++实现
- 职责:负责加载Java的核心类库(java.lang.* 、 java.util. * )
扩展类加载器(Extension ClassLoader)/平台类加载器(PlatForm ClassLoader)
- 职责:负责加载扩展类库(扩展包)
- JDK 9 重命名为**平台类加载器-(Platform ClassLoader)**引入了模块化系统(Project Jigsaw),原来的 jre/lib/ext 目录已经被彻底删除。平台类加载器不再加载扩展包,而是负责加载 Java 平台标准的模块(如 java.sql、java.xml) 等
应用类加载器(Application ClassLoader)
- 职责:负责加载自己写的业务代码,以及第三方Maven依赖
自定义类加载器(Custom ClassLoader)
- 职责:自己继承
java.lang.ClassLoader实现的加载器,可以自定义加载逻辑,eg:从网络上下载字节码、or 加载加密过的.class文件
类加载器是如何工作的?==========>双亲委派机制
当一个类加载器收到类加载请求时,不会自己去加载,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。
所以所有的加载请求最终都应该传送到最顶层的启动类加载器中。
父类加载器反馈自己无法完成这个加载请求时 ===> 子加载器
为什么要采用这种机制?
-
安全性:假如黑客恶意写了个
java.lang.String类,里面有木马病毒,当程序尝试加载这个类时,∵ 双亲委派机制 ,则一步步向上传递到启动类加载器(Bootstrap ClassLoader),它发现已经加载过官方的String类了,直接返回官方的
这块防的时“类加载安全”,防不住“代码注入”或“业务漏洞” -
避免重复加载:父加载过,子不需要重复加载
运行时数据区:整个工厂的各种车间(堆、栈、方法区等)
线程私有:
-
程序计数器(PC):如果JVM执行代码是坐地铁,那PC寄存器就是“下一站提示牌”
核心作用:
记录当前线程正在执行的JVM字节码指令的内存地址
字节码是一行行发给JVM执行的指令,PC是盯着执行哪一步了,接下来是哪一步 -
虚拟机栈:如果堆是存放数据的大仓库,那么 虚拟机栈(Stack) 就是执行代码的流水线。
特点:
线程私有:每个线程在被创建时,JVM都会给它创建一个对应的虚拟机栈,线程之间的数据时隔离的,所以时线程安全的
主管运行:保存方法的局部变量、部分结果、参与方法的调用和返回
先进后出:每当一个方法被调用,就会有一个“栈帧”push,方法执行完,栈帧被pop -
本地方法栈:服务于JVM调用 的Native方法
特点: 和虚拟机栈一致
线程私有:每个线程都有自己独立的本地方法栈。
生命周期:与线程生死相随,线程结束,本地方法栈随之销毁。
也是栈结构:遵循先进后出(FILO)原则,当一个 Native 方法被调用,它就会在本地方法栈里压入一个栈帧。
线程共享:
-
堆:JVM堆是JVM所管理的内存中最大的一块,在JVM启动时被创建,
唯一目的:存放对象实例
作用:
java的堆内存分代,是指将不同生命周期的堆内存对象存储在不同的的堆内存区域
助于垃圾回收的效率,可以为不同“代”设置不同回收策略 -
方法区:
-
方法区是《Java虚拟机规范》中定义的一个逻辑概念(类似于接口),不是具体实现(类似于实现类)。
所以他在HotSpot中的实现--------->元空间JDK 1.7 及之前的版本中,方法区通常被实现为永久代,用于存储类信息、常量池、静态变量、即时编译器编译后的代码等数据
1.7 中,把字符串常量池、静态变量都移到了堆内存中,这么做的主要原因是因为永久代的GC 回收效率太低,只有在FullGC的时候才会被执行回收。但是Java中往往会有很多字符串也是朝生夕死的,将字符串常量池放到堆中,能够更高效及时地回收字符串内存
1.8 开始HotSpot对方法区的实现进行了重大变化,永久代被移除,换成了元空间,元空间是使用本地内存来存储类的元数据信息的,不位于堆内存中

2963

被折叠的 条评论
为什么被折叠?



