超详细——JVM【1】:内存区域划分和类加载

🌹🤍🌹

一、JVM 是什么?

JVM 就是 Java 虚拟机,虚构出来的一种计算机,是 Java 运行的基础,也是实现一次编译到处执行的关键。

这块部分可以说是 Java 中最重要的一个部分,但是工作中基本用不上,面试会考~

  • 内存区域划分
  • 类加载
  • 垃圾回收
🌹🤍🌹

二、内存区域划分

就像装修房子一样,按照功能和作用,把内存区域进行划分范围,

  1. 栈(虚拟机栈、本地方法栈)
  2. 程序计数器
  3. 方法区

栈和程序计数器是每个线程都各自有一份的(线程私有),堆和方法区是整个JVM进程,它有一套的(线程共享)。

不同的变量位置在哪里? \color{RoyalBlue}不同的变量位置在哪里? 不同的变量位置在哪里?

  • 局部变量 栈上
  • 成员变量 堆上
  • 静态变量 方法区
🌹🤍🌹

三、类加载

类加载 本身是一个复杂的事情,学习中我们需要了解以下的就可以了:

3.1 🎨 什么是类加载?

Java 程序在运行之前,需要先编译,把 .java 变成 .class 文件(二进制字节码文件)
运行的时候, java 进程(JVM)就会读取对应的 .class 文件,并且解析内容,在内存中构造出类对象并进行初始化…

简单来说,就是把 类 从文件 加载到 内存 里

什么是类对象? \color{RoyalBlue} 什么是类对象? 什么是类对象?

类对象描述了这个类是啥样子的,有哪些属性(属性名字、类型、private/public),有哪些方法(方法名字、参数个数、参数类型、返回值类型、private/public),继承自哪个父类,实现哪些接口…

类对象也是创建实例的具体依据。

3.2 🎨 类加载具体过程

大体分为三个过程,细分五个

  1. 加载
  2. 连接
    1. 验证
    2. 准备
    3. 解析
  3. 初始化
3.2.1 📚 加载

我们需要注意的是,这里的 “加载” 只是 “类加载” 中的一个阶段,

在 加载 阶段, JVM 要找到 .class 文件,读取文件内容,并且按照 .class 规范的格式来解析

3.2.2 📚 验证

检查看当前的 .class 里的内容格式是否符合要求

[.class 文件长啥样,文档上有明确描述]

3.2.3 📚 准备

给类里的静态变量分配内存空间

分配内存空间不包括进行初始化,

es:
static int a = 520;
准备阶段就是给 a 分配内存空间(四个字节),同时这些空间初始情况是全 0

3.2.4 📚 解析

初始化字符串常量,把符合引用替换成直接引用

直接引用:相当于内存地址
符合引用:相当于占位符

es:
假如代码中有一行 String s = "hi";
在类加载之前,“hi” 这个字符串常量是没有分配内存空间的,得类加载完成之后才有内存空间,s 里也就无法保留字符串常量的真实地址,只能先使用一个占位符,标记一下(这块是 “hi” 这个常量的地址),等真正给 “hi” 分配过内存之后,然后就可以用这个真正的地址替代之前的占位符

3.2.5 📚 初始化

针对类进行初始化,初始化静态成员,执行静态代码块,并且加载父类…

3.3 🎨 何时触发类加载?

使用到一个类的时候,就触发加载

类并不一定是程序一启动就加载了…是第一次使用就进行加载!!!
[有点像懒汉模式]

使用到一个类分为以下几种情况: \color{RoyalBlue} 使用到一个类分为以下几种情况: 使用到一个类分为以下几种情况:

  • 创建这个类的实例
  • 使用了类的静态方法 / 静态属性
  • 使用了类的子类(加载子类会触发加载父类)
3.4 🎨 重点考察的部分:双亲委派模型(面试高频)

双亲委派模型 决定了按照啥样的规则来在哪些目录里去找 .class 文件

3.4.1 📚 类加载器

JVM 加载类,是由 类加载器(class loader)这样的模块来负责的

JVM 自带了多个类加载器,主要有如下三个:

  1. Bootstrap ClassLoader(负责加载标准库中的类)
  2. Extension ClassLoader(负责加载 JVM 扩展的库的类)
  3. Application ClassLoader(负责加载咱们自己项目里的自定义类)

上面三个类加载器各自负责一个各自的片区

描述上述类加载器相互配合的工作过程,就是 双亲委派模型

总结:

  • 上述三个类加载器存在父子关系
  • 进行类加载的时候,输入的内容 全限定类名,形如 java.lang.Thread
  • 加载的时候,从 Application ClassLoader 开始
  • 某个类加载器开始加载的时候,不会立即扫描自己负责的路径,而是先把任务委派给父 “类加载器” 让其进行处理
  • 找到最上面的 Bootstrap ClassLoader ,在往上,没有父 “类加载器” 了,只能自己动手加载了
  • 如果父亲找到类,就进行下面的验证、准备…如果父亲没找到类,就交给自己的儿子,继续加载
  • 如果一直找到最下面的 Application ClassLoader 也没有找到类,就会抛出一个 “类没找到” 异常,类加载就失败了

按照这个顺序加载,最大的好处在于,如果程序员写了一个类,这个类正好全限定类名和标准库中的类冲突了(比如你自己写个类,叫做 java.lang.Thread),此时仍然保证类加载可以加载到标准库的类,防止代码加载错了带来问题

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刹那芳间-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值