面试官:Java文件是如何被加载到内存中的?

面试连环call

  1. Java类是如何被加载到内存中的?
  2. Java类的生命周期都有哪些阶段?
  3. JVM加载的class文件都有哪些来源?
  4. JVM在加载class文件时,何时判断class文件的格式是否符合要求?

类生命周期

一个类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期将会经历加载、验证、准备、解析、初始化、使用和卸载七个阶段,其中验证、准备、解析三个部分统称为连接

类的生命周期

  • 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按步就班地开始,
  • 解析阶段顺序则不固定,它可以在初始化之前,而在某些情况下也可以在初始化阶段之后,这是为了支持Java语言的运行时绑定特性

类加载过程

系统加载 Class 类型的文件主要三步:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析

img

加载

加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情

  • 通过一个类的全限定名来获取其定义的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。

java_jvm_classload_1

加载.class文件的方式

  • 本地文件系统中直接加载
  • 通过网络下载.class文件
  • zip,jar等归档文件中加载.class文件
  • 从专有数据库中提取.class文件
  • Java源文件动态编译为.class文件

链接

验证

确保被加载的类的正确性

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  • 文件格式验证(Class 文件格式检查)
  • 元数据验证(字节码语义检查)
  • 字节码验证(程序语义检查)
  • 符号引用验证(类的正确性检查)

验证阶段示意图

准备

为类的静态变量分配内存,并将其初始化为默认值

  • 这时候进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。
  • 这里所设置的初始值通常情况下是数据类型默认的零值(如00Lnullfalse等),而不是被在Java代码中被显式地赋予的值。

基本数据类型的零值

注意:JDK 7 之前,HotSpot 使用永久代来实现方法区的时候,类变量所使用的内存都应当在 永久的 中进行分配。 而在 JDK 7 及之后,HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到中,这个时候类变量则会随着 Class 对象一起存放在 Java 堆中。

解析

虚拟机将常量池内的符号引用替换为直接引用的过程

解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符 7 类符号引用进行

  1. 符号引用
  • 符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可
  1. 直接引用
  • 直接指向目标的指针(比如,指向Class类型、类变量、类方法的直接引用可能是指向方法区的指针)
  • 相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
  • 一个能间接定位到目标的句柄

类的初始化

当一个JVM在启动之后,其中可能包含的类非常多,是不是每个类都会被初始化呢?答案是否定的。

JVM对类的初始化是一个延迟机制,当一个类在首次使用的时候才会被初始化,在同一个运行时package下,一个Class只会被初始化一次。

《Java虚拟机规范》则是严格规定了有且只有6种情况下必须立即对类进行初始化(而加载、验证、准备自然需要在此之前开始)

  1. 通过new关键字会导致类的初始化

  2. 访问类的静态变量,包括读取和更新会导致类的初始化

  3. 访问类的静态方法,也会导致类初始化

  4. 初始化子类会导致父类被初始化

  5. 对某个类进行反射操作。会导致类被初始化

  6. 启动类,就是执行main函数所在的类会导致该类被初始化

注意:构造某个类的数组时并不会导致该类的初始化

初始化步骤

  • 如果这个类还没有被加载和链接,那先进行加载和链接
  • 如果这个类存在直接父类,且这个类还没有被初始化,那就初始化直接的父类
  • 执行类中初始化语句(如static变量和static块)

参考内容

#面试##Java#
全部评论

相关推荐

05-09 15:06
湘南学院 Java
点赞 评论 收藏
分享
原来已经一年了,因为没有加任何实验室没有学长学姐带,再一次偶然的机会下刷到我们学校的牛肉哥,和他聊天之后发现他也没加实验室能进大厂,我就燃起了希望,去年大概 4 月份找好路线 零基础 开始学 5 月背八股和开始刷算法很难受 7-8 月焦虑躯体化害怕找不到实习 9 月找到一家像样的小厂去实习了 4 个月大三上期末考试结束之后 1 月份回来边实习边准备工作压力很大 当时只有字节、百度、商汤的面试,字节三面挂了,百度 oc,商汤 二面挂(差评 无效面试),之后来深圳百度实习之后还是觉得不甘心一直没把算法和八股扔下一直在准备,百度实习的时候 mt 交给我一个特别重要的工作数据库迁移(特别感谢 mt ,这个需求学到了很多东西处理了一堆线上问题),本来看着暑期他们面试都很困难,然后听说百度要涨实习薪资(然而 5 月并没有涨),就想着留在百度吧也懒得面试了,4 月 20 多的时候字节 hr 打电话约面问我要不要尝试一下询问了 1 月份三面为啥会挂有没有学习 ai 知识(因为字节这边后端岗位偏 ai),我来到百度之后全面拥抱 AI 也认识了我的好兄弟 X 哥,他在百度 XX 部门 Agent 实习,他属于是我 Agent 的启蒙老师,来百度之后一直在了解 AI 这一块,我就接受了字节的面试,一面的时候 20 分钟实习拷打然后突然说 30 分钟代码考核我心就凉了以为是 kpi,算法题是手撕高并发安全下的令牌桶限流器,我写了整整 80 多行代码最后也写出来了,但是从来没看到过出这种题能 oc 的我也就不管了,后边面试也是很顺利但是流程有点长可能一直在横向吧总结结果是好的!!!感谢这一年努力的自己和遇到的各位互联网大佬分享的知识!!!ps 图二纯感慨 (觉得🍬请不要喷我)欢迎大家一起交流学习呀!!!!
点赞 评论 收藏
分享
评论
3
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务