首页 简历|笔试面试

面渣逆袭 JVM篇暗黑V2.1

  • 25年9月4日 发布
  • 15.95MB 共123页
面渣逆袭 JVM篇暗黑V2.1面渣逆袭 JVM篇暗黑V2.1面渣逆袭 JVM篇暗黑V2.1面渣逆袭 JVM篇暗黑V2.1面渣逆袭 JVM篇暗黑V2.1

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

No. 1 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

前⾔

2.3 万字 115 张⼿绘图,详解 54 道 Java 虚拟机⾯试⾼频题(让天下没有难背的⼋股),⾯

渣背会这些 JVM ⼋股⽂,这次吊打⾯试官,我觉得稳了(⼿动 dog)。整理:沉默王⼆,戳

转载链接,作者:三分恶,戳原⽂链接。

亮⽩版本更适合拿出来打印,这也是很多学⽣党喜欢的⽅式,打印出来背诵的效率会更⾼。

2024 年 12 ⽉ 30 ⽇开始着⼿第⼆版更新。

对于⾼频题,会标注在《Java ⾯试指南(付费)》中出现的位置,哪家公司,原题是什

么,并且会加 ,⽬录⼀⽬了然;如果你想节省时间的话,可以优先背诵这些题⽬,尽

快做到知彼知⼰,百战不殆。

区分⼋股精华回答版本和原理底层解释,让⼤家知其然知其所以然,同时⼜能做到⾯试时

的⾼效回答。

结合项⽬(技术派、pmhub)来组织语⾔,让⾯试官最⼤程度感受到你的诚意,⽽不是

机械化的背诵。

No. 2 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

修复第⼀版中出现的问题,包括球友们的私信反馈,⽹站留⾔区的评论,以及 GitHub 仓

库中的 issue,让这份⾯试指南更加完善。

增加⼆哥编程星球的球友们拿到的⼀些 offer,对⾯渣逆袭的感谢,以及对简历修改的⼀

些认可,以此来激励⼤家,给⼤家更多信⼼。

优化排版,增加⼿绘图,重新组织答案,使其更加⼝语化,从⽽更贴近⾯试官的预期。

⻓按识别下⾯的⼆维码,关注⼆哥的公众号,回复【222】即可拉取最新版本。

No. 3 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

当然了,请允许我的⼀点点私⼼,那就是星球的 PDF 版本会⽐公众号早⼀个⽉时间,毕竟星

球⽤户都付费过了,我有必要让他们先享受到⼀点点福利。相信⼤家也都能理解,毕竟在线

版是免费的,CDN、服务器、域名、OSS 等等都是需要成本的。

更别说我付出的时间和精⼒了,⼤家觉得有帮助还请给个⼝碑,让你身边的同事、同学都能

受益到。

No. 4 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

我把⼆哥的 Java 进阶之路、JVM 进阶之路、并发编程进阶之路,以及所有⾯渣逆袭的版本都

放进来了,涵盖 Java基础、Java集合、Java并发、JVM、Spring、MyBatis、计算机⽹络、

操作系统、MySQL、Redis、RocketMQ、分布式、微服务、设计模式、Linux 等 16 个⼤的

主题,共有 40 多万字,2000+张⼿绘图,可以说是诚意满满。

展示⼀下暗⿊版本的 PDF 吧,排版清晰,字体优雅,更加适合夜服,晚上看会更舒服⼀点。

No. 5 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

⼀、引⾔

1.什么是 JVM?

JVM,也就是 Java 虚拟机,它是 Java 实现跨平台的基⽯。

程序运⾏之前,需要先通过编译器将 Java 源代码⽂件编译成 Java 字节码⽂件;

程序运⾏时,JVM 会对字节码⽂件进⾏逐⾏解释,翻译成机器码指令,并交给对应的操作系

统去执⾏。

No. 6 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

这样就实现了 Java ⼀次编译,处处运⾏的特性。

说说 JVM 的其他特性?

①、JVM 可以⾃动管理内存,通过垃圾回收器回收不再使⽤的对象并释放内存空间。

②、JVM 包含⼀个即时编译器 JIT,它可以在运⾏时将热点代码缓存到 codeCache 中,下次

执⾏的时候不⽤再⼀⾏⼀⾏的解释,⽽是直接执⾏缓存后的机器码,执⾏效率会⼤幅提⾼。

No. 7 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

③、任何可以通过 Java 编译的语⾔,⽐如说 Groovy、Kotlin、Scala 等,都可以在 JVM 上

运⾏。

No. 8 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

为什么要学习 JVM?

学习 JVM 可以帮助我们开发者更好地优化程序性能、避免内存问题。

⽐如说了解 JVM 的内存模型和垃圾回收机制,可以帮助我们更合理地配置内存、减少 GC 停

顿。

⽐如说掌握 JVM 的类加载机制可以帮助我们排查类加载冲突或异常。

再⽐如说,JVM 还提供了很多调试和监控⼯具,可以帮助我们分析内存和线程的使⽤情况,

从⽽解决内存溢出内存泄露等问题。

1. Java ⾯试指南(付费)收录的京东同学 10 后端实习⼀⾯的原题:有了解 JVM

2. Java ⾯试指南(付费)收录的字节跳动同学 20 测开⼀⾯的原题:了解过 JVM

么?讲⼀下 JVM 的特性

2.说说 JVM 的组织架构(补充)

No. 9 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

增补于 2024 年 03 ⽉ 08 ⽇。

推荐阅读:⼤⽩话带你认识 JVM

JVM ⼤致可以划分为三个部分:类加载器、运⾏时数据区和执⾏引擎。

① 类加载器,负责从⽂件系统、⽹络或其他来源加载 Class ⽂件,将 Class ⽂件中的⼆进制

数据读⼊到内存当中。

② 运⾏时数据区,JVM 在执⾏ Java 程序时,需要在内存中分配空间来处理各种数据,这些

内存区域按照 Java 虚拟机规范可以划分为⽅法区、堆、虚拟机栈、程序计数器和本地⽅法

栈。

③ 执⾏引擎,也是 JVM 的⼼脏,负责执⾏字节码。它包括⼀个虚拟处理器、即时编译器 JIT

和垃圾回收器。

No. 10 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的腾讯 Java 后端实习⼀⾯原题:说说 JVM 的组织

架构

2. Java ⾯试指南(付费)收录的得物⾯经同学 9 ⾯试题⽬原题:JVM的架构,具

体阐述⼀下各个部分的功能?

⼆、内存管理

3. 能说⼀下 JVM 的内存区域吗?

推荐阅读:深⼊理解 JVM 的运⾏时数据区

按照 Java 虚拟机规范,JVM 的内存区域可以细分为 程序计数器 、 虚拟机栈 、 本地⽅法栈 、

堆 和 ⽅法区 。

No. 11 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

其中 ⽅法区 和 堆 是线程共享的, 虚拟机栈 、 本地⽅法栈 和 程序计数器 是线程私有的。

介绍⼀下程序计数器?

程序计数器也被称为 PC 寄存器,是⼀块较⼩的内存空间。它可以看作是当前线程所执⾏的字

节码⾏号指示器。

介绍⼀下 Java 虚拟机栈?

Java 虚拟机栈的⽣命周期与线程相同。

No. 12 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

当线程执⾏⼀个⽅法时,会创建⼀个对应的栈帧,⽤于存储局部变量表、操作数栈、动态链

接、⽅法出⼝等信息,然后栈帧会被压⼊虚拟机栈中。当⽅法执⾏完毕后,栈帧会从虚拟机

栈中移除。

⼀个什么都没有的空⽅法,空的参数都没有,那局部变量表⾥有没有变量?

对于静态⽅法,由于不需要访问实例对象 this,因此在局部变量表中不会有任何变量。

对于⾮静态⽅法,即使是⼀个完全空的⽅法,局部变量表中也会有⼀个⽤于存储 this 引⽤的

变量。this 引⽤指向当前实例对象,在⽅法调⽤时被隐式传⼊。

No. 13 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

详细解释⼀下:

⽐如说有这样⼀段代码:

public class VarDemo1 {

public void emptyMethod() {

// 什么都没有

}

public static void staticEmptyMethod() {

// 什么都没有

}

}

⽤ javap -v VarDemo1 命令查看编译后的字节码,就可以在 emptyMethod 中看到这样的内

容:

这⾥的 locals=1 表示局部变量表有⼀个变量,即 this,Slot 0 位置存储了 this 引⽤。

⽽在静态⽅法 staticEmptyMethod 中,你会看到这样的内容:

No. 14 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

这⾥的 locals=0 表示局部变量表为空,因为静态⽅法属于类级别⽅法,不需要 this 引⽤,也

就没有局部变量。

介绍⼀下本地⽅法栈?

本地⽅法栈与虚拟机栈相似,区别在于虚拟机栈是为 JVM 执⾏ Java 编写的⽅法服务的,⽽

本地⽅法栈是为 Java 调⽤本地 native ⽅法服务的,通常由 C/C++ 编写。

在本地⽅法栈中,主要存放了 native ⽅法的局部变量、动态链接和⽅法出⼝等信息。当⼀个

Java 程序调⽤⼀个 native ⽅法时,JVM 会切换到本地⽅法栈来执⾏这个⽅法。

介绍⼀下本地⽅法栈的运⾏场景?

当 Java 应⽤需要与操作系统底层或硬件交互时,通常会⽤到本地⽅法栈。

⽐如调⽤操作系统的特定功能,如内存管理、⽂件操作、系统时间、系统调⽤等。

详细说明⼀下:

⽐如说获取系统时间的 System.currentTimeMillis() ⽅法就是调⽤本地⽅法,来获取操作

系统当前时间的。

No. 15 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

再⽐如 JVM ⾃身的⼀些底层功能也需要通过本地⽅法来实现。像 Object 类中的

hashCode() ⽅法、 clone() ⽅法等。

native ⽅法解释⼀下?

推荐阅读:⼿把⼿教你⽤ C语⾔实现 Java native 本地⽅法

native ⽅法是在 Java 中通过 native 关键字声明的,⽤于调⽤⾮ Java 语⾔,如 C/C++ 编写

的代码。Java 可以通过 JNI,也就是 Java Native Interface 与底层系统、硬件设备、或者本

地库进⾏交互。

介绍⼀下 Java 堆?

No. 16 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

堆是 JVM 中最⼤的⼀块内存区域,被所有线程共享,在 JVM 启动时创建,主要⽤来存储

new 出来的对象。

Java 中“⼏乎”所有的对象都会在堆中分配,堆也是垃圾收集器管理的⽬标区域。

从内存回收的⻆度来看,由于垃圾收集器⼤部分都是基于分代收集理论设计的,所以堆⼜被

细分为 新⽣代 、 ⽼年代 、 Eden空间 、 From Survivor空间 、 To Survivor空间 等。

No. 17 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

随着 JIT 编译器的发展和逃逸技术的逐渐成熟,“所有的对象都会分配到堆上”就不再那么绝对

了。

从 JDK 7 开始,JVM 默认开启了逃逸分析,意味着如果某些⽅法中的对象引⽤没有被返回或

者没有在⽅法体外使⽤,也就是未逃逸出去,那么对象可以直接在栈上分配内存。

堆和栈的区别是什么?

堆属于线程共享的内存区域,⼏乎所有 new 出来的对象都会堆上分配,⽣命周期不由单个⽅

法调⽤所决定,可以在⽅法调⽤结束后继续存在,直到不再被任何变量引⽤,最后被垃圾收

集器回收。

栈属于线程私有的内存区域,主要存储局部变量、⽅法参数、对象引⽤等,通常随着⽅法调

⽤的结束⽽⾃动释放,不需要垃圾收集器处理。

介绍⼀下⽅法区?

⽅法区并不真实存在,属于 Java 虚拟机规范中的⼀个逻辑概念,⽤于存储已被 JVM 加载的

类信息、常量、静态变量、即时编译器编译后的代码缓存等。

在 HotSpot 虚拟机中,⽅法区的实现称为永久代 PermGen,但在 Java 8 及之后的版本中,

已经被元空间 Metaspace 所替代。

No. 18 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

变量存在堆栈的什么位置?

对于局部变量,它存储在当前⽅法栈帧中的局部变量表中。当⽅法执⾏完毕,栈帧被回收,

局部变量也会被释放。

public void method() {

int localVar = 100; // 局部变量,存储在栈帧中的局部变量表⾥

}

对于静态变量来说,它存储在 Java 虚拟机规范中的⽅法区中,在 Java 7 中是永久带,在

Java8 及以后 是元空间。

public class StaticVarDemo {

public static int staticVar = 100; // 静态变量,存储在⽅法区中

}

1. Java ⾯试指南(付费)收录的京东同学 10 后端实习⼀⾯的原题:堆和栈的区别

是什么

2. Java ⾯试指南(付费)收录的⽐亚迪⾯经同学 3 Java 技术⼀⾯⾯试原题:介绍

⼀下 JVM 运⾏时数据区

3. Java ⾯试指南(付费)收录的字节跳动⾯经同学 1 Java 后端技术⼀⾯⾯试原

题:讲⼀下 JVM 内存结构?

4. Java ⾯试指南(付费)收录的京东⾯经同学 1 Java 技术⼀⾯⾯试原题:说说

JVM 运⾏时数据区

5. Java ⾯试指南(付费)收录的美团⾯经同学 2 Java 后端技术⼀⾯⾯试原题:

JVM 内存结构了解吗?

6. Java ⾯试指南(付费)收录的快⼿⾯经同学 1 部⻔主站技术部⾯试原题:请说

⼀下 Java 的内存区域,程序计数器等?

7. Java ⾯试指南(付费)收录的字节跳动⾯经同学 8 Java 后端实习⼀⾯⾯试原

题:jvm 内存分布,有垃圾回收的是哪些地⽅

8. Java ⾯试指南(付费)收录的得物⾯经同学 8 ⼀⾯⾯试原题:说⼀说 jvm 内存

区域

No. 19 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

9. Java ⾯试指南(付费)收录的美团⾯经同学 3 Java 后端技术⼀⾯⾯试原题:

jmm 内存模型 栈 ⽅法区存放的是什么

10. Java ⾯试指南(付费)收录的收钱吧⾯经同学 1 Java 后端⼀⾯⾯试原题:你提

到了栈帧,那局部变量表除了栈帧还有什么?⼀个什么都没有的空⽅法,完全空

的参数什么都没有,那局部变量表⾥有没有变量?

11. Java ⾯试指南(付费)收录的招银⽹络科技⾯经同学 9 Java 后端技术⼀⾯⾯试

原题:Java堆内存和栈内存的区别

12. Java ⾯试指南(付费)收录的 OPPO ⾯经同学 1 ⾯试原题:说⼀下JVM内存模

13. Java ⾯试指南(付费)收录的深信服⾯经同学 3 Java 后端线下⼀⾯⾯试原题:

JVM变量存在堆栈的位置?

14. Java ⾯试指南(付费)收录的TP联洲同学 5 Java 后端⼀⾯的原题:Jvm内存区

域,本地⽅法栈的运⾏场景,Native⽅法解释⼀下

15. Java ⾯试指南(付费)收录的字节跳动同学 17 后端技术⾯试原题:jvm结构 运

⾏时数据区有什么结构 堆存什么

16. Java ⾯试指南(付费)收录的腾讯⾯经同学 29 Java 后端⼀⾯原题:new⼀个

对象存放在哪⾥?(运⾏时数据区),局部变量存在JVM哪⾥

4.说⼀下 JDK 1.6、1.7、1.8 内存区域的变化?

JDK 1.6 使⽤永久代来实现⽅法区:

No. 20 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

JDK 1.7 时仍然是永久带,但发⽣了⼀些细微变化,⽐如将字符串常量池、静态变量存放到了

堆上。

在 JDK 1.8 时,直接在内存中划出了⼀块区域,叫元空间,来取代之前放在 JVM 内存中的永

久代,并将运⾏时常量池、类常量池都移动到了元空间。

No. 21 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

5.为什么使⽤元空间替代永久代?

客观上,永久代会导致 Java 应⽤程序更容易出现内存溢出的问题,因为它要受到 JVM 内存

⼤⼩的限制。

HotSpot 虚拟机的永久代⼤⼩可以通过 -XX:MaxPermSize 参数来设置,32 位机器默认的⼤

⼩为 64M,64 位的机器则为 85M。

⽽ J9 和 JRockit 虚拟机就不存在这种限制,只要没有触碰到进程可⽤的内存上限,例如 32

位系统中的 4GB 限制,就不会出问题。

主观上,当 Oracle 收购 BEA 获得了 JRockit 的所有权后,就准备把 JRockit 中的优秀功能移

植到 HotSpot 中。

如 Java Mission Control 管理⼯具。

No. 22 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

但因为两个虚拟机对⽅法区实现有差异,导致这项⼯作遇到了很多阻⼒。

考虑到 HotSpot 虚拟机未来的发展,JDK 6 的时候,开发团队就打算放弃永久代了。

JDK 7 的时候,前进了⼀⼩步,把原本放在永久代的字符串常量池、静态变量等移动到了堆

中。

JDK 8 就终于完成了这项移出⼯作,这样的好处就是,元空间的⼤⼩不再受到 JVM 内存的限

制,⽽是可以像 J9 和 JRockit 那样,只要系统内存⾜够,就可以⼀直⽤。

6. 对象创建的过程了解吗?

当我们使⽤ new 关键字创建⼀个对象时,JVM ⾸先会检查 new 指令的参数是否能在常量池

中定位到类的符号引⽤,然后检查这个符号引⽤代表的类是否已被加载、解析和初始化。如

果没有,就先执⾏类加载。

No. 23 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

如果已经加载,JVM 会为对象分配内存完成初始化,⽐如数值类型的成员变量初始值是 0,

布尔类型是 false,对象类型是 null。

接下来会设置对象头,⾥⾯包含了对象是哪个类的实例、对象的哈希码、对象的 GC 分代年

龄等信息。

最后,JVM 会执⾏构造⽅法 <init> 完成赋值操作,将成员变量赋值为预期的值,⽐如 int

age = 18 ,这样⼀个对象就创建完成了。

对象的销毁过程了解吗?

当对象不再被任何引⽤指向时,就会变成垃圾。垃圾收集器会通过可达性分析算法判断对象

是否存活,如果对象不可达,就会被回收。

垃圾收集器通过标记清除、标记复制、标记整理等算法来回收内存,将对象占⽤的内存空间

释放出来。

可以通过 java -XX:+PrintCommandLineFlags -version 和 java -XX:+PrintGCDetails

-version 命令查看 JVM 的 GC 收集器。

可以看到,我本机安装的 JDK 8 默认使⽤的是 Parallel Scavenge + Parallel Old 。

不同参数代表对应的垃圾收集器表单:

No. 24 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

新⽣代 ⽼年代 JVM参数

Serial Serial -XX:+UseSerialGC

Parallel Scavenge Serial -XX:+UseParallelGC -XX:-UseParallelOldGC

Parallel Scavenge Parallel Old -XX:+UseParallelGC -XX:+UseParallelOldGC

Parallel New CMS -XX:+UseParNewGC -XX:+UseConcMarkSweepGC

G1 -XX:+UseG1GC

1. Java ⾯试指南(付费)收录的⽐亚迪⾯经同学 3 Java 技术⼀⾯⾯试原题:对象

创建到销毁的流程

2. Java ⾯试指南(付费)收录的美团⾯经同学 2 Java 后端技术⼀⾯⾯试原题:说

说创建对象的流程?

3. Java ⾯试指南(付费)收录的携程⾯经同学 1 Java 后端技术⼀⾯⾯试原题:对

象创建到销毁,内存如何分配的,(类加载和对象创建过程,CMS,G1 内存清

理和分配)

7.堆内存是如何分配的?

在堆中为对象分配内存时,主要使⽤两种策略:指针碰撞和空闲列表。

No. 25 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

指针碰撞适⽤于管理简单、碎⽚化较少的内存区域,如年轻代;⽽空闲列表适⽤于内存碎⽚

化较严重或对象⼤⼩差异较⼤的场景如⽼年代。

什么是指针碰撞?

假设堆内存是⼀个连续的空间,分为两个部分,⼀部分是已经被使⽤的内存,另⼀部分是未

被使⽤的内存。

在分配内存时,Java 虚拟机会维护⼀个指针,指向下⼀个可⽤的内存地址,每次分配内存

时,只需要将指针向后移动⼀段距离,如果没有发⽣碰撞,就将这段内存分配给对象实例。

什么是空闲列表?

No. 26 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

JVM 维护⼀个列表,记录堆中所有未占⽤的内存块,每个内存块都记录有⼤⼩和地址信息。

当有新的对象请求内存时,JVM 会遍历空闲列表,寻找⾜够⼤的空间来存放新对象。

分配后,如果选中的内存块未被完全利⽤,剩余的部分会作为⼀个新的内存块加⼊到空闲列

表中。

1. Java ⾯试指南(付费)收录的携程⾯经同学 1 Java 后端技术⼀⾯⾯试原题:对

象创建到销毁,内存如何分配的,(类加载和对象创建过程,CMS,G1 内存清

理和分配)

memo:2025 年 1 ⽉ 10 ⽇修改到此

8.new 对象时,堆会发⽣抢占吗?

会。

new 对象时,指针会向右移动⼀个对象⼤⼩的距离,假如⼀个线程 A 正在给字符串对象 s 分

配内存,另外⼀个线程 B 同时为 ArrayList 对象 l 分配内存,两个线程就发⽣了抢占。

JVM 怎么解决堆内存分配的竞争问题?

为了解决堆内存分配的竞争问题,JVM 为每个线程保留了⼀⼩块内存空间,被称为 TLAB,

也就是线程本地分配缓冲区,⽤于存放该线程分配的对象。

No. 27 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

当线程需要分配对象时,直接从 TLAB 中分配。只有当 TLAB ⽤尽或对象太⼤需要直接在堆

中分配时,才会使⽤全局分配指针。

这⾥简单测试⼀下 TLAB。

可以通过 java -XX:+PrintFlagsFinal -version | grep TLAB 命令查看当前 JVM 是否开

启了 TLAB。

如果开启了 TLAB,会看到类似以下的输出,其中 bool UseTLAB 的值为 true。

我们编写⼀个简单的测试类,创建⼤量对象并强制触发垃圾回收,查看 TLAB 的使⽤情况。

No. 28 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

class TLABDemo {

public static void main(String[] args) {

for (int i = 0; i < 10_000_000; i++) {

allocate(); // 创建⼤量对象

}

System.gc(); // 强制触发垃圾回收

}

private static void allocate() {

// ⼩对象分配,通常会使⽤ TLAB

byte[] bytes = new byte[64];

}

}

在 VM 参数中添加 -XX:+UseTLAB -XX:+PrintTLAB -XX:+PrintGCDetails -

XX:+PrintGCDateStamps ,运⾏后可以看到这样的内容:

waste:未使⽤的 TLAB 空间。

alloc:分配到 TLAB 的空间。

refills:TLAB 被重新填充的次数。

可以看到,当前线程的 TLAB ⽬标⼤⼩为 10,496 KB( desired_size: 10496KB );未发⽣

慢分配( slow allocs: 0 );分配效率直接拉满( alloc: 1.00000 52494KB )。

当使⽤ -XX:-UseTLAB -XX:+PrintGCDetails 关闭 TLAB 时,会看到类似以下的输出:

No. 29 / 123

⾯渣逆袭 JVM篇第⼆版-让天下所有的⾯渣都能逆袭

直接出现了两次 GC,因为没有 TLAB,Eden 区更快被填满,导致年轻代 GC。年轻代 GC 频

繁触发,⼀部分⻓⽣命周期对象被晋升到⽼年代,间接导致⽼年代 GC 触发。

9.能说⼀下对象的内存布局吗?

好的。

对象的内存布局是由 Java 虚拟机规范定义的,但具体的实现细节各有不同,如 HotSpot 和

OpenJ9 就不⼀样。

就拿我们常⽤的 HotSpot 来说吧。

对象在内存中包括三部分:对象头、实例数据和对⻬填充。

No. 30 / 123

开通会员 本次下载免费

所有资料全部免费下载! 推荐用户付费下载获取返佣积分! 积分可以兑换商品!
普通用户: 8.93元
网站会员:
本次下载免费

开通网站会员 享专属特权

  • 会员可免费

    下载全部资料!

  • 推荐用户下载

    获取返佣积分!

  • 积分可以

    兑换商品!

一键复制 下载文档 联系客服