JavaEE初阶11.0

JVM

一、JVM

1.0 简介
(1) 简介

Java虚拟机 主要是面试题导向 jvm诞生的初心就是为了让你不用理解底层

《深入理解Java虚拟机》一书问世,面试官带火了 ,断章取义拿出来作为面试题

这本书治疗失眠效果非常好

重点理解:jvm内存区域划分 类加载机制 垃圾回收机制

2.0 内存区域
(1) 简介

为什么要进行划分区域?

JVM Java虚拟机:仿照真实的机器 真实的操作系统进行设计

真实的操作系统中,对于进程的空间地址进行了分区域的设计 JVM仿造了这样的设计8

划分不同区域之后 就有不同的分工

(2)四个核心区域

JVM具体是怎么划分的呢?

核心区域四个:

程序计数器(内存空间) 很小的区域 只是用来记录当前指令执行到哪个地址了

元数据区: 我们Java写的代码 经过Javac编译成.class文(二进制数据) class文件要加载到内存中(类加载) 而元数据区就是保存当前类被加载好的数据(类对象)~

保存方法的调用关系 每次调用方法 就会进入到方法内部执行 当方法执行完毕 返回到调用位置 继续往后面走

其实理解上来说 也是数据结构那里栈的先进后出 属于是数据结构栈的应用

虚拟机 就是虚拟一套世界~ 栈这个空间 一般来说就是几MB几十MB这样的情况(也可以更改)

保存new对象的

//这里的栈和堆不是数据结构里面的栈和堆

堆是JVM中最大的空间区域了

如果堆上的对象 不再使用了的话 就需要被释放掉(垃圾回收)

图片辅助理解:

元数据区和堆 整个Java进程共用一份 程序计数器和栈 一个进程可能有很多份(每个线程有一份)

3.0 类加载
(1) 类加载过程

站在面试角度 类加载 主要关心两个方面

类加载的步骤有哪些

三个大的阶段 第二个阶段又分成了三个步骤

a) 加载

找到.class文件 根据类的全限定名(包名+类名 形如java.lang.String)打开文件 读取文件内容并存到内存里~

b)验证:解析,校验.class文件读到的内容是否是合法的 并把这里的内容转成 结构化的数据(.class文件 二进制文件 格式是有明确要求的)

//Java官方文档:Java SE 文档 --- API 和文档 | Oracle 中国

c)准备

给类对象申请内存空间 此处申请的内存空间 相当于是"全0"的空间

d)解析:针对字符串常量 进行初始化

字符串常量 本身就包含在.class文件中 就需要.class文件里解析出来的字符串常量 放到内存空间里(元数据区 常量池中)

e)初始化

针对刚才所谈到类对象 针对类对象的各种属性进行填充 包括类中的静态成员

如果这个类还有父类 并且父类还没有加载呢 此环节也会触发父类的类加载

(背下来)

类加载中的"双亲委派模型"

//这个东西本身不是一个很紧要的机制 但是之所以成为了一个知名面试题 最主要的原因是起了一个好名字 ~ 哈哈哈 感觉很高大上 自动装箱/自动拆箱 Java内存模型 spirng里面的IOC AOP 代理模式

//补充

类加载的时机 : 可以理解为懒汉模式时机 懒汉加载 "用到的时候再加载"

构造这个类的实例 调用/使用 静态属性/静态方法 使用某个类的时候,如果他的父类还没有加载 也会触发父类的加载

(2) 双亲委派模型

双亲委派模型 描述了类加载中 根据全限定类名 找到.class文件的过程

//全限定类名:用于唯一标识一个类的完整名称

更准确的来说 单亲委派模型/父亲委派模型

* 类加载器

是一个代码块 这个代码块的功能专门就是用来进行类加载的

这个可以自定义的 可以自定义好之后 放到双亲委派模型

*过程

从appliacation入口 如果第三库里面没有 就上一级到extension里面找 以此类推

这里的爷父孙不是继承关系 是一种引用指向关系

可以按照下面的这个来进行类比

Boot可以理解为大老板 Extension可以理解为中层管理人员 Application可以理解为基层员工

4.0 垃圾回收机制(GC)
(1)引入

之前学习C语言的时候 我们了解到C语言需要申请内存malloc 申请之后一定要手动调用free释放内存空间 这样的机制 程序员在写代码的时候 总是容易忘记手动释放内存

而Java语言吸取了C的示例 jvm有自动垃圾回收机制 之后的各种编程语言也沿用了这种方式

但是自动垃圾回收机制也是有代价的: 效率下降 有的时候还是"卡了"STW问题

c++为了解决内存泄漏问题 引入了智能指针机制

rust的解决办法:通过严格的编译器检查 来对代码中的内存问题进行叫校验 编译的过程中做检查发现问题了直接报错 但是这么做也是有代价的 就是语法变得非常复杂 GC依然是主流机制

(2) 工作过程

简单来说就是找到垃圾 释放垃圾

(3) 如何找到垃圾

引用计数 (Python PHP采取的方案)

同样 这么做也是有代价的

内存消耗的更多:需要额外分配空间来记录引用记数 如果引用计数分配的空间是4个字节 newTest8个字节 这样相当于提高了50%的空间占用率

可能造成循环引用:

相当于死锁的那个情况 此时 ab这两个对象的引用不为0 虽然不为0 但是这两对象都无法使用

可达性分析(Java采取的方案)

上面的引用计数是空间换时间 这里的可达性分析是时间换空间

可达性分析的过程是:以特定对象(栈 局部变量 常量 静态成员)为起点 尽可能地遍历 判定某个对象是否能访问到

每次访问一个对象 都会把这个对象标记成"可达" 当完成所有对象的遍历之后 未被标记成"可达"的对象就是垃圾 之后回收掉

这个过程是周期性的 每隔一段时间就触发一次

下面的图片表示这个过程:

代价:每次触发 都要遍历一遍对象 如果对象很多的情况 这样以此遍历的成本也是非常大的

(4)如何释放垃圾?

释放垃圾的机制:标记-清除 复制算法 标记-整理

Java给出的答卷:分代回收 把上面的机制结合起来

标记-清除

把垃圾对象得内存 直接释放掉 这样会产生内存碎片问题

虽然存在一定的空闲空间 但是这些空闲时间不是连续的

后面我们申请内存的时候 有麻烦 因为申请内存的时候 是申请一段连续的内存空间

如果内存碎片非常多 就会导致你总的空闲时间虽然很大 但是你但凡想申请一个稍微大一点的内存

都是失败 总4G 出现上述的情况 申请1G空间都可能失败

复制算法:

一次只是使用空间的一半

把不是垃圾的对象 拷贝到另外一侧 然后再把这一侧给整体的释放掉

解决了内存碎片问题

但是也有缺点:

一旦不是垃圾的对象比较多 内存搬运数据很多的话 复制的成本也会还大

还有就是内存直接砍半 2G的内存立马变成1G(内存的空间利用率低)

标记-整理

结合了上面两个方法 既能解决内存碎片 也能保证内存利用率

删除了那些垃圾之后 把其他元素搬运到原来消除的位置

缺点:内存搬运数据的操作开销是挺大的 一旦对象很多很大 复制成本很大

分代回收:

Java给出的答卷 分代回收 把上面123种方法结合起来(主要是2 3 )

代: 对象的年龄 GC抡次 (GC轮次越多 表示越老) 某个对象经历了一轮GC可达性分析之后 不是垃圾 此时对象的年龄就+1

针对不同年龄采取不同的策略

如果某个对象 已经是年龄比较大的了 此时大概率还会继续存在很久~

通俗理解就是"要死早死了" 留下来的都是老油条 不容易死去

其实反应在生活中 就以面试为例 一个公司只有50个岗位 但是有1000份简历 公司不可能一个一个都面试笔试完毕(成本很大) 所以就先初步筛选 第一轮过滤到一大部分 然后再次细分之后

开始多轮面试 过了好几轮还在的 最后留任 公司的某位淘汰也是这个道理但是时间周期是比较长的

新创建的对象就放到"伊甸区" 绝大部分的伊甸区 都活不过第一轮GC

伊甸区=>幸存区:复制算法

幸存区中的对象:也是要经历GC的扫描 每一轮GC都会消灭一大部分对象 剩余的对象再次通过复制算法 复制到另外一个幸存区

如果这个对象在幸存区中经历了多次复制 都存活下来了 对象的年龄的就大了 就会晋升到老年代

以上就是JavaEE初阶的全部内容 好事多磨~

相关推荐
XQ丶YTY1 天前
javaee程序设计 中南民族大学 复习
java·程序设计·javaee·期末·复习·速成·中南民族大学
爱学习的小可爱卢24 天前
JavaEE进阶——SpringAOP从入门到源码全解析
javaee·spring-aop
sugar__salt1 个月前
网络编程套接字(二)——TCP
java·网络·网络协议·tcp/ip·java-ee·javaee
努力小周1 个月前
基于STM32的智能台灯系统设计与实现
stm32·单片机·嵌入式硬件·c#·毕业设计·毕设·javaee
兮山与1 个月前
JavaEE初阶10.0
javaee
兮山与1 个月前
JavaEE初阶8.0
javaee
兮山与1 个月前
JavaEE初阶9.0
javaee
爱学习的小可爱卢1 个月前
JavaEE进阶——SpringMVC响应处理详解
spring boot·postman·javaee
带刺的坐椅1 个月前
Solon 不依赖 Java EE 是其最有价值的设计!
java·spring·web·solon·javaee