JVM揭秘之旅:打破性能瓶的终极指南(1)

#王者杯·14天创作挑战营·第3期#

JVM揭秘之旅:打破性能瓶的终极指南(一)

专栏简介

「为什么Java程序员必须啃透JVM?」
JVM是Java生态的“灵魂引擎”,但多数开发者仅停留在API调用层面。当面临频发GC卡顿诡异OOM崩溃线程死锁顽疾时,是否曾因底层原理的模糊而束手无策?本专栏将带您穿透技术迷雾,系统攻克JVM核心领域:

  • ⚙️ 硬核原理拆解:从字节码执行、类加载双亲委派,到G1/ZGC回收器设计,逐层剖析JVM的运作机制;
  • 🛠️ 调优实战手册:结合大厂案例,详解参数配置(如-XX:+HeapDumpOnOutOfMemoryError)、内存泄漏定位(MAT工具)、并发瓶颈破解;
  • 🚀 前沿技术追踪:涵盖元空间、JIT编译、协程(Loom项目)等新特性,提前掌握未来技术栈;
  • 💡 面试高频攻略:深度解析京东/华为等大厂JVM面试题。

适合读者
✅ 渴求突破CRUD的Java工程师
✅ 被性能问题困扰的架构师
✅ 备战P7/P8级技术面试的求职者

专栏承诺不用空洞理论堆砌,每篇均附可复现的代码案例及调优脚本。跟随专栏,您将获得从“被动救火”到“主动防御”的JVM掌控力!

1、JVM简介

什么是jvm

学习JVM有什么用

常见的JVM

以下JVM以Hotspot为准。

JVM的学习路线


2、程序计数器

程序计数器的作用

在物理上,程序计数器是通过寄存器实现的。

程序计数器的特点

线程私有。每个线程都有自己的程序计数器。不同线程抢cpu,抢到了,就根据程序计数器的地址,执行下一条代码。

不会存在内存溢出。
3、虚拟机栈

栈:先进后出。

虚拟机栈:线程运行时需要的内存空间。

栈帧:每个方法运行时需要的内存。

栈的演示

栈的问题辨析

1.垃圾回收不涉及栈内存。因为方法结束,栈帧的生命就结束了。

2.栈内存大,可以进行递归调用的层数多,但程序可执行线程越少(总内存不变,栈内存大,线程数少)

详解:

对于基本数据类型,安全。

局部变量存在栈中,属于线程私有。

对于对象。

判断下列三个方法是否线程安全?

m1,显然安全。局部变量线程私有。

m2,不安全,形参是被传入的,其它线程也可有访问到sb。

m3,不安全。虽然sb是局部变量,但是被返回了,其它线程可以访问到。

栈内存溢出

1.栈帧过多。

实际一般是递归调用没有合理的递归终止条件。

有时候不是自己的代码有问题,而是没有正确引用第三方库。

比如转json时。

TypeScript import com.fasterxml.jackson.databind.ObjectMapper; class Dept { private String name; private Emp manager; // 构造方法、getter和setter public Dept(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Emp getManager() { return manager; } public void setManager(Emp manager) { this.manager = manager; } } class Emp { private String name; private Dept dept; // 构造方法、getter和setter public Emp(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } } public class StackOverflowDemo { public static void main(String[] args) throws Exception { // 创建相互引用的对象 Dept dept = new Dept(“研发部”); Emp emp = new Emp(“张三”); dept.setManager(emp); emp.setDept(dept); // 尝试序列化为JSON - 这将导致栈溢出 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(dept); System.out.println(json); } }

正确做法。

TypeScript class Emp { // … @JsonIgnore public Dept getDept() { return dept; } }

2.栈帧过大导致内存溢出。一般不会出现。

线程运行诊断——cpu运行高

top命令定位到进程。

定位到线程。

H 表示以"线程模式"显示信息。默认 ps 只显示进程,加上 H 后会显示进程中的所有线程

-e 显示所有用户进程,包括其它用户进程。

-o 自定义输出格式

知道了线程编号,接下来。定位到代码中的线程名

先将线程id32665换算成16进制。

Jstack 进程id.

看到没,第8行代码。

线程死锁排查——程序运行很长时间无结果

nohub在后台运行代码。

本来应该输出结果,一直没有。可能是死锁。

上面运行代码,可以看到进程id 32752.

Jstack 32752.

报错信息很明显。

根据上面信息的代码行数定位下问题。

很明显,它们互锁了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半旧518

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值