【JavaEE进阶】JVM-面试中的高频考点1

目录

JVM内存区域划分

JVM具体是怎么划分的(四个核心区域)

程序计数器

元数据区

JVM类加载

方面一:类加载步骤有哪些

1.加载

2.验证

3.准备

4.解析

5.初始化

方面二:类加载中的"双亲委派模型"(超高频考点)

JVM默认提供了三种类加载器:

双亲委派模型的过程

双亲委派的流程图

小结(要是没空看上面的就看这个)

JVM内存区域划分

类加载

面试小tips:


JVM章节主要是面试导向的,纯八股文

在JVM中,面试中最多出的是这三个方面

  • JVM内存区域划分
  • 类加载机制
  • 垃圾回收机制

接下来,我们来进一步了解这三个方面

JVM内存区域划分

  • JVM(也就是Java虚拟机)是仿照真实机器,真实的操作系统来设计的
  • 在真实的操作系统中,对进程的地址空间进行了分区域的设计
  • JVM也就仿照了操作系统的情况,进行了分区域的设计

JVM从操作体系中申请到了一些内存空间

  • JVM空间划分,就是把申请到的内存空间,按照功能分成不同的小区域

JVM具体是怎么划分的(四个核心区域)

程序计数器

  • 程序计数器是一个很小的区域,用来记录 当前指令执行到哪了
  • 类似计算机组成原理里的 PC寄存器,但PC寄存器是CPU里的东西

元数据区

  • 元数据区是用来保存 当前类 已经加载好的数据的
  • Java代码 =>(编译成)class文件 => 加载到内存中
  • 想要运行这Java代码,就要把.class加载到内存中(这就是类加载的过程)
  • 元信息,指的就是一些属性
  • 比如。类叫什么名字,是不是public,继承自哪些类,实现了哪些接口......

  • 栈是用来保存方法的调用关系
  • 每次调用方法时,就会进入方法内部执行,当方法执行完后,返回到调用位置,继续往后走
  • 栈 后进先出的特点 很适合表示函数的调用关系

例如 main函数中调用test1函数

  • 栈帧内会放着 函数要用到的参数,局部变量,返回值返回的地址(test1结束后,继续执行哪里)
  • 这个空间不算很大,一般就是几MB,十几MB这样(可以通过JVM的启动参数来配置)

  • 堆 -> 保存 new对象
  • 堆是JVM中最大的空间区域了
  • 往集合类中添加元素,就是放到堆中
  • 如果堆中的对象,不再使用了的话,就会被释放掉(垃圾回收)
  • 堆中会有 比如方法叫啥名字,参数有几个,都叫啥,都是啥类型,返回值是啥类型

举个栗子~

  • 因为Test()是一个被new的对象 ,所以会被放在堆中
  • 如果a是一个局部变量 ,那就放到
  • 如果a是一个成员变量 ,那就放到
  • 如果a是一个静态成员变量 ,那就放到元数据区

整个Java进程共用一份元数据区和堆

一个Java进程 中可能会有多份程序计数器和堆(每个线程都有一份)

注意区分JVM中的栈、堆 和 数据结构的栈、堆 !!!

  • JVM中的栈、堆 和 数据结构的栈、堆没啥关系
  • 虽然概念相似,但不是一个东西

JVM类加载

类加载本身是一个复杂的过程

面试中,类加载主要关心两个方面

方面一:类加载步骤有哪些

三个大的阶段,其中第二个阶段,又分成三个步骤,所以一共是五个步骤

1.加载

  • 找到.class文件(因为类信息在.class文件中)
  • 根据类的全限定名(包名 + 类名,形如java.lang.String)
  • 打开文件,把文件读取到内存中(还不涉及解析)

2.验证

  • 解析,校验.class文件中读到的内容是否合法 ,若合法,就把**.class文件中的内容转成结构化的数据**
  • 虽然.class是一个二进制文件,但是格式是有明确要求的

3.准备

  • 类对象申请内存空间
  • 内存空间初始化,就是一个全"0"的空间

4.解析

  • 针对字符串常量进行初始化
  • 字符串常量本身就包含子在.class文件中
  • 这一步就是要把 .class文件中解析出来的字符串常量放到 元数据区的常量池中

5.初始化

  • 针对上一步解析出来 的类对象进行最终 的初始化
  • 填充类对象的属性(包含 类中的静态成员)
  • 如果这个类还有父类,并且父类还没加载,此环节也会触发父类的类加载

方面二:类加载中的"双亲委派模型"(超高频考点)

  • 双亲委派模型描述了 类加载中,根据全限定类名,找到.class文件的过程
  • 个人理解的话,觉得"父亲委派模型"这个名字更贴切

JVM默认提供了三种类加载器:

|------------------------|-------------------|-------------------------------------|
| 类名 | 辈分 (作者自己加的,帮助理解) | 类来自哪里 |
| BootstrapClassLoader | 爷(爹继承爷) (爷继承null) | Java标准库的目录 |
| ExtensionClassLoader | 爹(子继承爹) | Java扩展库的目录 (对标准库做的扩充) |
| ApplicationClassLoader | 子 | Java的第三方库/ 当前项目 (通过Maven下载来的都是第三方库) |
[三种类加载器]

双亲委派模型的过程

  • 在进行类加载时,通过全限定类名,去找.class时
  • 把(子)ApplicationClassLoader作为入口开始往上一辈传递
  • (子)ApplicationClassLoader把 找目标.class 的任务委派给它爹 (爹)ExtensionClassLoader
  • (爹)ExtensionClassLoader 也把 找目标.class 的任务委派给它爹 (爷)BootstrapClassLoader
  • (爷)BootstrapClassLoader也把 找目标.class 的任务委派给它爹,但是 爷的上一辈是null,发现爷没有爹了o(╥﹏╥)o
  • 没办法,(爷)BootstrapClassLoader只能在自己的Java标准库中找这个 .class
  • 要是(爷)BootstrapClassLoader 没找到,就把这个找.class 的任务交给它儿子,也就是(爹)ExtensionClassLoader
  • (爹)ExtensionClassLoader也在自己的Java扩展库中找这个 .class
  • 要是(爹)ExtensionClassLoader没找到,就把这个找.class 的任务交给它儿子,也就是(子)ApplicationClassLoader
  • (子)ApplicationClassLoader也在自己的Java第三方库中找这个 .class
  • 在上面爷、爹、子的任一阶段,要是找到了目标.class,就把类加载出来,要是没找到就报错

哈哈^_^,是不是看迷糊了,作者我小小概括一下(编个故事,别当真哈,逻辑差不多是这个意思就行)

  • 出于对长辈的尊重
  • 找.class似乎是 类加载器 家族中 无上荣誉的事情
  • "子"捧着.class 交给"父"
  • "父"捧着.class 交给"爷"
  • "爷"因为头顶上只有null了,所以就开始从自己的 "私库"中找有没有对应的.class,如果有,就掏出来并进行类加载,如果没有,就让自己的儿子,也就是"父"来找
  • "父"、"子"同上
  • 如果在任一层找到了目标.class,就直接加载,要是"子"搜完了也没找到,那就报错

双亲委派的流程图

  • 这一套流程,目的是为了约定"优先级"
  • 收到一个类名之后,一定是先在 标准库 中找
  • 再从 扩展库找
  • 最后才在第三方库找

没有为啥,大佬就是这么写的

假设有另一个版本的JVM,就没有这一套"往上传"的过程,直接就从BootstrapClassLoader开始往下找,也是完全可行的

小结(要是没空看上面的就看这个)

JVM内存区域划分

  • 程序计数器:是一个小区域,存放着 下一个要执行的指令地址
  • 元数据区:类对象(类名是啥,继承了哪个类,实现了哪些接口,有哪些属性,属性都叫什么名字,属性的类型,是private还是public,有哪些方法,方法名是什么,参数列表......)
  • :方法之间的调用关系
  • :new出来的对象
    • 非静态成员 ,位于堆上(成员存放的位置,是前几年的常见面试题)
    • 静态成员 位于元数据区
    • 局部变量 处于栈上

类加载

  • .class文件 => 内存中的类对象
  • 加载 :依据全限定类名,找.class文件,并读取文件内容
  • 验证 :校验读到的内容的格式 是否符合要求
  • 备准分配内存(分配全"0"的,未初始化的内存空间)
  • 解析针对字符串常量进行初始化
  • 初始化 :针对类对象进行填充 ,也会触发父类的加载(前提是父类还没有被加载)

一个进程中,一个类的加载,只会触发一次

类加载触发的时机

  • Java程序一启动,就会加载用到的所有类吗?NO!
  • 类加载是一个懒汉模式/懒加载
  • Java代码用到哪个类,就会触发哪个类的加载
  • 怎么算用到这个类呢
    • 构造 这个类的实例
    • 调用 /使用 类的静态属性/静态方法
    • 使用某个类的时候,如果它的父类还没加载,也会触发父类的加载

面试小tips:

面试中被问到:你是哪一届的,为什么现在来,学校怎么办

  • 为什么现在来:我认为一个程序员,学习编程技术,光靠书本是不行的,要尽早的去参加商业级别的项目,在实战中打磨自己的技术能力
  • 学校怎么办:我们学校院长也是上述观点,非常支持同学们出去找实习,学校的课只要拿到offer之后,院长签个字,期末回来考试就行了
  • (就算你学校院长并没有说过这句话,也要这么说,先拿下offer再说)

太棒了!你居然能耐心地看完这些内容!

说明你的学习能力和自控能力超强呢!

加油加油!我们一起拿下40w年薪!

END✿✿ヽ(°▽°)ノ✿

相关推荐
老李四1 小时前
Java 内存分配与回收策略
java·jvm·算法
陈逸轩*^_^*1 小时前
深入理解 Java JVM,包括垃圾收集器原理、垃圾回收算法原理、类加载机制等
java·jvm
2***57421 小时前
Java内存泄漏排查工具
java·开发语言
鸢尾掠地平1 小时前
防火墙的相关知识点与iptables源地址转换实验
网络
动感小麦兜1 小时前
00-华为hi3798mv100刷NAS
网络
一起养小猫1 小时前
《枕边算法书》阅读笔记:一场从热爱到实践的算法启蒙之旅
笔记
S***H2831 小时前
Java在微服务网关中的实现
java·开发语言·微服务
cherry有点甜·1 小时前
标题调用外部接口apifox与浏览器显示不一致
java
家有两宝,感恩遇见2 小时前
不能明文传证件号码后端加密解密最简单的方式AES
java·服务器·开发语言