前言
在上一篇文章中,我分享了这些年,为了进大厂背过的Java面试题(基础篇),全在这儿了!,受到了很多小伙伴的关注和好评,这也让我更有动力继续为大家输出干货。
作为一名有着 10 年 Java 开发经验的老鸟,回想起当年为了进大厂疯狂背面试题的日子,真是感慨万千。
如今市面上的面试题分享大多泛泛而谈,对于真正想提升技术、应对大厂面试的小伙伴帮助有限。
各位coder们都知道,JVM(Java 虚拟机)是 Java 语言的核心,也是面试中的高频考点。尤其是在冲击像阿里这样的大厂时,对 JVM 的深入理解更是必不可少。
今天就把这些宝贵的经验和面试题分享给大家,希望能帮助大家少走弯路,顺利拿下心仪的 offer。
JVM 内存划分
JVM 运行时数据区域
JVM 的运行时数据区域就像是一个大型的“工厂车间”,各个区域分工明确,有条不紊地运行着。它主要分为程序计数器、Java虚拟机栈、本地方法栈、Java 堆、方法区这几个部分。
程序计数器可以看作是一个“记录员”,它记录着当前线程所执行的字节码的行号。
Java 虚拟机栈则像是一个“工作流水线”,每个方法在执行时都会创建一个栈帧,栈帧中存储着局部变量表、操作数栈等信息。
本地方法栈与 Java 虚拟机栈类似,只不过它是为本地方法服务的。
Java 堆是“原材料仓库”,对象都在这里分配内存,是 JVM 内存中最大的一块区域。
方法区则像是“技术资料室”,存储着已经被 JVM 加载的类信息、常量、静态变量等数据。
堆内存分配策略
堆内存的分配策略就像是仓库管理员分配货物存放位置的规则。常见的分配策略有指针碰撞和空闲列表。
指针碰撞适用于内存规整的情况,就好比仓库里货物摆放得整整齐齐,新货物直接放在空闲区域的起始位置即可。
空闲列表则适用于内存不规整的情况,此时仓库里货物摆放杂乱,需要有一个“清单”记录哪些区域是空闲的,以便分配新货物。
创建一个对象的步骤
创建一个对象就像是在工厂里生产一件产品,需要经过多个步骤。
首先是类加载检查,就好比确认生产这件产品的图纸(类信息)是否已经准备好。
然后为对象分配内存,这就像是在仓库里找一块地方存放产品。
接着进行内存初始化,将分配到的内存空间初始化为零值。
之后设置对象头信息,就像是给产品贴上标签,记录一些元数据。
最后执行对象的初始化代码,对对象进行真正的初始化操作。
下面我们手搓一下代码:
public class ObjectCreationExample {
public static void main(String[] args) {
// 创建一个对象
MyObject myObject = new MyObject();
}
}
class MyObject {
private int value;
public MyObject() {
value = 10;
}
}
对象引用
对象引用就像是产品的“提货单”,通过它我们可以找到堆内存中的对象。在 Java 中有强引用、软引用、弱引用和虚引用这几种类型。
强引用是最常见的引用方式,只要强引用存在,对象就不会被垃圾回收。
软引用则相对较弱,当内存不足时,软引用所引用的对象会被回收。
弱引用更弱,只要垃圾回收器扫描到弱引用所引用的对象,不管内存是否充足,都会回收该对象。
虚引用则是最弱的引用,它主要用于在对象被回收时收到一个通知。
示例代码:
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class ObjectReferenceExample {
public static void main(String[] args) {
// 强引用
MyObject strongRef = new MyObject(