JVM底层原理常见知识点&面试题总结

本文详细讲述了Java对象的创建过程,涉及内存分配的指针碰撞和空闲列表策略,JVM中new对象时的线程安全设计,以及内存溢出、内存泄漏的识别与解决。同时介绍了强引用、软引用、弱引用和虚引用的区别,逃逸分析和垃圾回收机制等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



JVM底层原理

面试题

Java 对象的创建过程?

  1. 类加载检查:
    • 当虚拟机遇到 new 指令时,首先检查这个指令的参数,也就是要创建的对象的类是否已经加载过
    • 如果没有加载过,虚拟机会执行类加载过程
  2. 分配内存:
    • 类加载检查通过后,虚拟机会为新对象分配内存空间
  3. 对象内存初始化:
    • 分配内存完成后,虚拟机会将分配到的内存空间初始化为零值
  4. 设置对象头:
    • 虚拟机会在对象的内存空间中设置对象头,用于存储关于对象的元数据信息
  5. 执行初始化方法(构造函数):
    • 经过上述步骤,一个新的对象已经产生,但是从 Java 程序的角度来看,对象的创建还没有完成
    • 然后,会根据程序员定义的构造函数进行初始化

什么是指针碰撞?什么是空闲列表?/ 内存分配的两种方式?

指针碰撞:

  • 指针碰撞假定 Java 堆中的内存是绝对规整的
  • 内存的分界点由一个指针作为指示器来标示,指向已分配内存的末尾
  • 在分配对象内存时,只需要将指针向空闲空间方向移动对象内存大小的位置
  • 适用于基于压缩策略的收集器,例如 Serial 和 ParNew 收集器

空闲列表:

  • 空闲列表假设 Java 堆内存并不规整,已分配内存和空闲内存交错分布
  • 虚拟机维护一个空闲列表,记录哪些内存块是可用的,即未被分配的
  • 在分配对象内存时,虚拟机会在空闲列表中找到一块足够大的空间来分配给对象。分配后,虚拟机需要更新空闲列表上的记录,标记分配的区域为已用
  • 适用于基于清除算法的收集器,例如 CMS 收集器

JVM 里 new 对象时,堆会发生抢占吗?JVM 是怎么设计来保证线程安全的?/ 内存分配并发问题?

  • CAS:使用 CAS 操作来保证更新操作的原子性
  • 本地线程分配缓冲 (TLAB):
    每个线程在 Java 堆中预先分配一小块内存,称为本地线程分配缓冲
    要分配内存的线程,先在本地缓冲区中分配,只有本地缓冲区用完,分配新的缓冲区才需要同步锁定

对象的内存布局?

对象在堆内存中的布局可以划分为三个部分:对象头、实例数据和对齐填充

  • 对象头:包括两部分信息:存储对象自身的运行时数据;类型指针
  • 实例数据:用来存储对象真正的有效信息
  • 对齐填充:起占位符的作用

对象怎么访问定位?

使用句柄:

  • Java 堆中划分内存来作为句柄池
  • 句柄中包含对象实例数据的指针和对象类型数据的指针
    image-20230317153832919

直接指针:

  • 对象的实例数据直接存放在堆内存中
    image-20230317154017974

对比:

  • 使用句柄:在对象被移动的时候,不需要更新引用地址
  • 直接指针:效率高,节省了一次指针定位的时间开销(HotSpot 使用)

内存溢出和内存泄漏?

  • 内存溢出:申请的内存超过可用内存,内存不足
  • 内存泄漏:申请的内存空间没有被正确释放,导致内存空间被浪费

能手写内存溢出的例子吗?

  • Java 堆溢出:Java 堆用于存储对象实例,只要不断创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值