本篇通过介绍JVM是什么,认识JVM的内存区域的划分,了解类加载过程,JVM中垃圾回收机制,从中了解到垃圾回收机制中如何找到存活对象的方式,引用计数与可达性分析的方式,再释放垃圾对象时使用的方式,标准清除,复制算法,标准整理,分代回收等等,如有错误,请在评论区指正,让我们一起交流,共同进步!
JVM: Java虚拟机,通过软件模拟具有硬件功能,运行在一个完全隔离的环境中的完整计算机系统;
JVM内存区域图示:
问题:查看变量的形态,也就是根据代码判断属于堆,栈还是方法区?
① 堆: 成员变量;(new 出来的对象存放其中)
② 栈:局部变量;(维护方法直接的调用关系)
③ 方法区:静态变量;(放类加载后的类对象, 被static修饰的)
【注】变量处在什么区域与变量类型无关;
线程私有的内存:每个线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储;
【注】线程共享:堆与元数据区; 线程私有:栈(包括虚拟机栈,本地方法栈)与程序计数器;
例如:
void function() {
Student s = new Student();
}
//s是引用类型,是局部变量,处在栈上,而new Student()是对象,处在堆上;
类加载:把 .class 文件加载到内存 得到类对象的过程;
类加载过程:
① 加载:找到.class文件,读取文件内容;
② 验证:验证.class文件是否符号规范要求;.class文件有明确的数据格式;
③ 准备:给类对象分配内存空间(给类变量(static修饰的静态变量)分配的内存空间是未初始化,默认全是0,此时静态变量也是0);
例如:public static int value = 66; //此时准备是给value分配空间,初始化为0,不是66;
④ 解析:针对字符串常量进行初始化;
初始化常量的过程: Java 虚拟机将常量池内的 符号引用 替换为 直接引用 的过程;
符号引用:处于相对位置,字符串常量在.class文件中存在,这时只知道他们之间的相对位置也就是符号引用;
直接引用:处于实际位置,加载到内存中知道位置就是实际内存位置也就是直接引用;
⑤ 初始化:针对类对象进行初始化;(初始化静态成员,执行静态代码,类有父类也需要加载父类)
4.1 触发类加载时机 - 类加载是非必要,不加载
1)创建了类的实例
2)使用类的静态方法/静态属性
3)使用子类,触发父类的加载
4.2 双亲委派模型
双亲委派模型作用:在类加载阶段,找.class文件;
JVM加载类会使用类加载器这里简单介绍一下;
JVM中内置的三个类加载器:
① BootStrap ClassLoader: 负责加载Java标准库中的类
② Extension ClassLoader: 负责加载一些非标准的 Sun/Oracke扩展的库中的类;
③ Application ClassLoader: 负责加载项目中自己写的类,和第三方库中的类;
类加载过程图:
GC是垃圾收集的意思;帮助程序员自动释放内存的;
JVM主要释放哪个区域? =》释放 堆区域
5.2 垃圾回收的两个阶段
如何找垃圾:Java中使用对象,只能通过引用,所以通过判断一个对象是否有引用指向就可以了;所以引入下面两种方法;
图示:
【注】
计数器作用:引用增加,计数器就增加;引用减少,计数器就减少,当计数器为0时,就认为该对象没有引用了,认为时垃圾;
引用计数的缺点:
① 浪费空间 ② 存在循环引用的情况,会导致引用计数判定逻辑错误;
通过一个树形结构图来看一下:
通过root引用作为起点,就可以访问整个树的节点;
可达性条件:进行图示遍历需要有起点;
① 栈上的局部变量,都是起点;
② 常量池中的引用对象;
③ 方法区中,静态成员引用的对象;
可达性分析的缺点:
1)消耗更多时间,遍历过程消耗时间,不能第一时间发现某个垃圾对象;
2)在遍历的时候,如果过程中当前代码的对象引用关系变了,就会产生麻烦;
三种策略:
1)标记清除:先标记出回收对象,再直接释放垃圾对象内存;
产生问题:会产生大量内存碎片;清理完垃圾对象产生大量内存碎片,剩余的内存空间即使很多,但都是碎片化的,如果要申请一段连续的空间可能都申请不到;
图示:
2)复制算法: 解决了内存碎片问题;
复制算法过程:把整个内存空间分成两段(为了好描述过程,这里把内存空间分为a,b,a与b一样),一次只使用一半;如果使用a内存,将a内存中不是垃圾对象的拷贝到没有使用的另一边b内存中,然后再统一释放内存;
图示复制算法:
3)标记整理
标记整理思想:结合上述标记清除,标记整理在其上在加上一个从后向前搬运元素的过程;
标记整理图示:
分代回收机制:综合上述思想,针对不同的情况,使用不同的策略对垃圾进行回收;
分代回收图示:
分代回收过程:
1)·新创建的对象存放到伊甸区;
2)伊甸区的对象,经过第一轮GC,会通过复制算法,拷贝到生存区;生存区分为两半,大小相等,每次只使用一半;
在生存区中是垃圾对象就淘汰,不是垃圾对象就复制到另一半,一直重复上述过程;
3)对象在生存区,经过若干轮GC,年龄增长到 一定程度,就会通过复制算法拷贝到老年代区;
4)进入老年代的对象,年龄比较大,针对老年代的GC扫描频次会降低,消亡率就降低了;
老年代某个对象是垃圾对象了,进行标记整理法清除;
5)特殊情况:对象非常大,直接进入老年代区;原因是大对象进行复制算法成本高,其次大对象也不多;
✨✨✨各位读友,本篇分享到内容如果对你有帮助给个赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!