什么是JVM
JVM(Java Virtual Mchine)java虚拟机,主要作用就是将Java字节码文件解释为能被各种操作系统理解的机器码。
JVM的三大功能
1.解释和运行:将字节码文件翻译为能被各种操作系统理解的机器码。
2.内存分配:给对象及其方法分配内存,管理对象。
3.即时编译(JIT):将热点代码编译为字节码放到内存中,提高效率。
类加载器ClassLoad
类的生命周期
类的加载阶段:
将类的信息(硬盘、网络、反射)以二进制的形式加载到内存中。
注意:具体放在InstanceKlass(c语言编写)中,但因为Java程序不便直接操作c语言程序,所以使用Java.lang.Class进行映射。通过操作Java.lang.Class来控制InstanceKlass。
类的连接阶段:
连接阶段分为:验证、准备、解析。主要作用是验证Java代码是否符合规范、静态变量赋初始值(并不是直接赋原本变量值,而是赋0、1这种初值。final修饰变量在此阶段赋值)、将符号引用转变为内存地址值。
类的初始化阶段:
初始化阶段主要是给静态变量赋真值、执行静态方法(final修饰的静态变量在连接节段的准备状态中赋值)。
是否触发初始化,访问静态变量就会初始化。记住两个特例:final修饰的静态变量(final修饰静态变量赋值不为常量除外)、创建数组的类不会初始化。
触发初始化的情况:
- 使用Class.forName(),反射加载类
- 访问静态变量,访问final修饰的静态变量除外
- new对象
- 访问final修饰的静态变量右边不是常量,会初始化(特殊情况)
不触发初始化的情况:
- 无静态代码块或无静态变量赋值语句
- 有静态变量,但是没有赋值
- 使用final关键字修饰的静态变量(final修饰的静态变量右边不是常量除外)
- 创建数组的类,类本身不会初始化(特殊情况)
类加载器
双亲委派机制(重点)
什么是双亲委派机制?
加载类时,向父类寻找是否加载过该类,如果加载过类直接返回加载过的类,避免重复加载。寻找到启动类加载器后,从启动类加载器向下加载该类,保证加载类时的优先级顺序。
Application的父类是Extension,Extension加载器的父类是BootStrap。
双亲委派机制的优点:
1.避免恶意修改JDK的核心类库
2.避免类被重复加载
如何打破双亲委派机制
为什么要打破双亲委派机制?
双亲委派机制中类加载都是由Application、Extension、BootStrap加载,这样做不够灵活。例如在高度模块化的组件中,每个模块有自己的类加载器,操作自己的类加载器进行热操作,不去影响其他模块,这样操作更灵活。
如何打破双亲委派机制?
注意:
1.如果想实现自定义的类加载器,但是不想打破双亲委派机制,可以重写findClass方法。
2.类加载器和全限定类名相同,在Java中才会被认为是一个类。(类加载器不同,类名相同不是一个类)
重写ClassLoad类中loadClass()方法
双亲委派机制的核心逻辑,只要我们将这段代码重写就可以打破双亲委派机制
protected Class<?> loadClass(String name, boolean resolve)
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
if (parent != null) {
c = parent.loadClass(name, false); //当前类加载器没有加载到类,就去父类寻找
} else {
c = findBootstrapClassOrNull(name);
}
}
JVM内存区域(重点)
线程不共享区
程序计数器:程序计数器记录当前线程字节码执行位置。作用是,在线程切换后该线程可以继续执行之前因线程切换而未完成的任务。
栈(当方法递归执行时会造成内存泄漏):通过栈(先进后出)来记录方法栈帧。方法栈帧包括局部变量表(存放局部变量)、操作数栈(存放临时数据)、帧数据(变量内存地址/动态链接、方法出口、异常表)。
本地方法栈:记录本地方法的方法栈帧。
线程共享区
堆(创建过多对象时会造成内存泄漏):存储对象、数据、集合。(重点是堆的垃圾回收)
方法区:储存类信息、运行时常量池(放置在元空间中)、字符常量池(堆内存)。
JVM垃圾回收(重点)
如何判断可以垃圾回收的内存区域
引用计数法:给对象添加计数器,统计对象引用次数,如果为0表示没有引用该对象可以回收。存在的问题是,两个对象相互引用就无法回收。
可达性分析法(JVM采用方案):将对象分为两类,GCroot对象,普通对象;如果普通对象的引用路线中有GCroot对象,就不会被回收。
GCroot对象包括:
- 线程对象
- java.lang,Class对象
- 监视器对象,,用来保存同步锁synchronized关键字持有的对象
- 本地方法栈中的全局变量
JVM垃圾回收算法
标记清除算法:标记不可回收空间,删除其他对象所占空间。
优点,实现简单;缺点,产生内存碎片。
复制算法:将内存空间分为From,To两片空间。每次GC时会将不可回收对象放到To空间中,然后将To改为From(From改名为To,确保From永远存储不可回收对象)。
优点,解决内存碎片;缺点,空间利用效率低(只能利用一半内存)
标记整理算法:标记不可回收空间,并将这些空间转移到同一端,删除其他对象内存空间。
优点,解决内存碎片;缺点,需要执行多次空间转移算法时间利用率低。
分代GC(重点)
分代GC中堆空间内存图
分代GC过程中对象经历的全过程(这是小编呕心沥血画的示意图,友友们觉着不错快点赞吧!)
G1垃圾回收器(重点)
G1垃圾回收器的特点:
- 将内存区域划分为Region,区域不连续而是独立的小块。
- 支持多核CPU并发进行垃圾回收。
- 允许自主设置最大停止时间(G1通过判断Eden、Survivor区回收时间进行预估)
G1垃圾回收算法:
G1判断内存空间占年轻代60%,触发youngGC,回收年轻代内存,采用复制算法。
G1判断内存空间占总堆的45%,触发MixedGc,回收年轻代+老年代内存,采用复制算法。
G1判断内存空间占满,触发fullGC,回收年轻代+老年代内存,采用标记整理法。
并发垃圾回收过程
第一步:初始标记GCroot对象,阻塞执行。
第二步:标记GC存活对象,并发执行。
第三步:最终标记的是标记GC存活对象并发过程中所修改的对象,不去管理新创建或者不再关联的对象,阻塞执行。
第四步:并发清除垃圾对象,并发执行。
标签:对象,内存空间,回收,静态,内存,JVM,机制,加载 From: https://blog.csdn.net/weixin_62440319/article/details/141021120