面试—JVM

2024-09-07 09:20
文章标签 java jvm 面试

本文主要是介绍面试—JVM,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

JVM内存结构

类的生命周期

双亲委派机制

打破双亲委派机制

垃圾回收机制

判断垃圾回收算法

垃圾回收算法

G1垃圾回收器


JVM内存结构

  1. 程序计数器

    记录要执行的字节码指令的地址,可以控制程序指令的进行,实现分支、跳转、异常等

    在多线程执行时,会记录线程切换前执行到的那一条指令

  2. Java虚拟机栈

    每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、帧数据(动态连接、方法出口、异常表的引用)的信息

  3. 本地方法栈

    与java虚拟机栈作用相似

    区别 java虚拟机栈存储Java方法(字节码)调用时的栈帧

    本地方法栈存储的是native本地方法的栈帧

  4. 内存中空间最大的,创建的对象都存储在堆内存上

    三个值used,total,max,由Java虚拟机分配内存,一般设置total=max

  5. 方法区

    存放基础信息的位置,线程安全,主要由三个部分

    1. 类的元信息

      存放每个类的基本信息,一般为instanceKlass对象,在类的加载阶段完成

      主要是字节码文件的基本信息:包括魔数、版本号、父类、接口、常量池、字段、方法、虚方法表等信息

    2. 运行时常量池

      主要是类的加载和连接阶段,将符号引用编译为地址引用,通过地址快速定位到常量池中的内容

    3. 字符串常量池

      主要存放常量字符串(JDK7之后将字符串常量池放入到堆内存中)

类的生命周期

  • 主要分为五个阶段,加载—>连接—>初始化—>使用—>卸载

  • 在连接阶段又分为三个部分,验证—>准备—>解析

  1. 加载

    1. 类加载器根据类的全限定类名以二进制流的方式获取字节码文件

    2. 加载完之后,java虚拟机将字节码的信息保存在内存的方法区中

    3. 同时java虚拟机还会在堆中生成一份与方法区中数据类似的java.lang.Class对象(开发者主要的访问,可以很好的控制开发者访问数据的范围)

  2. 连接

    1. 验证

      验证是否为字节码文件,验证魔术(0XCACFBABE),版本号等信息

    2. 准备

      给静态变量赋值

    3. 解析

      将符号引用解析为内存地址引用

  3. 初始化

    执行静态代码块的内容,并为静态变量赋值

  4. 使用

    类的创建,赋值,调用等

  5. 卸载

    垃圾回收

双亲委派机制

  • 类加载器分为启动类加载器、扩展类加载器、应用程序类加载器和自定以类加载器

  • 每一个加载器中都有一个parent的常量,用于指向父类加载器

  1. 应用程序类加载器的父类加载器是扩展类加载器

  2. 自定义类加载器—>应用程序类加载器—>扩展类加载器—>启动类加载器

双亲委派机制

  1. 当一个类被加载的时候,会自下向上进行查找,委派父类加载器去尝试加载,如果启动类加载器收到请求能够找到并加载这个类,则加载过程结束,返回class对象

  2. 如果启动类加载器不能进行加载,就会向下委派子类加载器进行加载

  • 优点

    • 避免恶意代码替换JDK核心类库,如java.lang.String

    • 避免类被重复加载

打破双亲委派机制

  • ClassLoder主要负责将类的字节码加载到 JVM(Java 虚拟机)中,并创建对应的Class对象。

  • 核心原理

    • loadClass() 类加载器的入口,内部调用findClass()方法

    • findClass() 根据类的全限定类名,找到字节码文件

    • defineClass() 做一些类的校验,然后调用虚拟机底层方法将字节码信息加载到内存中

    • resolveClass() 执行类生命周期的连接阶段(验证、准备、解析)

  1. 自定义类加载器打破

    自定义类继承ClassLoder,重写loadClass()方法

    1. 传递类的全限定类名,找到字节码文件,并加载到内存中,变成二进制的数组

    2. 调用defineClass将二进制的数组传递,在方法区和堆中生成对应的数据

  2. 线程上下文类的加载器(JDBC)

    启动类加载器加载DriverManager,又需要通过SPI机制拿到应用程序类加载器去加载jar包中的mysql驱动(由启动类加载器委派应用程序类加载器去加载类,打破了双亲委派机制)

    SPI机制

    1. 在驱动的jar包中暴露出需要被加载的类,放到固定的文件中

    2. DriverManager中使用ServiceLoader方法加载文件中的类名,并且使用类加载器加载对应的类并创建对象

    • 由于启动类加载器在加载完DriverManager完之后,通过初始化阶段触发了应用程序类加载器的加载,类的加载过程依然符合双亲委派机制,只是触发了SPI机制,所以没有打破双亲委派机制

  3. OSGI模块化

    在OSGI中,每个模块都有自己独立的加载器,当一个模块的类加载器收到加载请求时,会先在自己模块进行查找,找不到回去别的模块进行查找。相当于同级之间的类加载器委派加载

垃圾回收机制

判断垃圾回收算法

  1. 引用计数法

    在堆内存中,对象被引用一次,就会计数器+1。如果计数器为0,则进行回收

    若时堆内存的对象互相引用,则无法回收,会造成内存溢出

  2. 可达性分析算法

    将对象分为垃圾回收的根对象(GCRoot对象)和普通对象

    与GCRoot对象形成一个引用链

    1. 强引用,引用的对象不会被回收

    2. 软引用,SoftReference对象(与GCRoot对象是强引用关联)来实现软引用,当对象使用完之后不会马上进行垃圾回收,而是当内存不足的时候进行垃圾回收,回收软引用的对象

    3. 弱引用,与软引用相似,但是弱引用不论内存是否不足都会被直接回收

    4. 虚引用

    5. 终结引用

垃圾回收算法

  1. 标记—清除算法

    使用可达性分析算法,标记出存活的对象(与GcRoot强引用的对象),删除内存中的非存活对象

  2. 复制算法

    把内存分为两个空间From(对象分配的空间)和To

    1. GC阶段,先将GCRoot对象搬运到To空间

    2. 将与GCRoot对象关联的对象也搬运到To空间

    3. 将两块空间的名字互换

    4. 清理From空间

  3. 标记—整理算法

    由于标记清楚算法清理后的内存时碎片化的,分配时内存空间不合适

    先标记存活对象,将存活的对象移动到堆的一端,清理非存活的对象

  4. 分代回收算法

    分为新生代(Young区)和老年代(Old区)

    新生代又分为伊甸园区(Eden区)和幸存者区(Survivor)

    1. 伊甸园区主要是存放新创建的对象

    2. 当伊甸园区存满时,会触发新生代的垃圾回收

      幸存者区主要使用复制算法进行垃圾回收

    3. 每次新生代垃圾回收一次会为对象记录年龄,当年龄到达阀值(最大15),对象就会晋升为老年代

G1垃圾回收器

  • 主要是分代回收算法,但是将内存分为大小相同的区域(Region)大小是堆空间/2048

  1. 当G1判断年轻代内存不足60%时,会触发新生代的垃圾回收

  2. 幸存者区存活的对象会被搬运的另一个幸存者区

  3. 当对象年龄到达15,放到老年代中

  4. 部分对象的大小如果超过区域的一半时,会直接放入单独的老年代中(Humongous区)

  5. 多次回收后,出现多个老年代,达到阀值时(默认45%),会触发混合回收,将新生代与老年代的对象使用复制算法回收

这篇关于面试—JVM的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1144677

相关文章

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱