如何排查线上问题
Created|Updated
|Word Count:30|Reading Time:1mins|Post Views:
cpu 偏高问题排查
数据库问题排查
Author: magicliang
Copyright Notice: All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Related Articles
2026-05-17
从 OSGi 到 Jigsaw:Java 模块化、SPI 与类加载器切换的真相
写在前面 本文回答三件事。第一件,为什么 Java 在 classpath 之上又要造 OSGi、JBoss Modules、Jigsaw(JPMS)这些"模块化"层;它们各自把哪一类问题摆在最高优先级。第二件,"切换类加载器"这件事到底是什么意思——是切线程上下文,是用新加载器装新类,还是把老的整个加载器换掉;不同的语义下,老的对象实例分别会发生什么。第三件,SPI(service-provider interface)为什么是模块化和 CL 切换的真正交汇点——ServiceLoader 默认靠 TCCL 找实现,DriverManager 是反 SPI 的活化石,JPMS 把 SPI 直接编进了 module-info,OSGi 干脆用 Service Registry 替换了它。 后两件事是工程里反复出问题的源头:Tomcat reload 之后类没卸掉、OSGi 升级 bundle 之后老对象 ClassCastException、JDBC Driver 把整个 webapp 钉在内存里、Spring Boot DevTools ...

2018-10-13
卡表和 RSet
卡表和 RSet 问题定义:为什么需要跨区域引用记录 JVM 垃圾收集器的核心工作之一是确定 live set——哪些对象仍然存活、不可回收。确定 live set 的标准做法是从 GC Roots(栈帧中的局部变量、静态字段等)出发,沿引用链遍历所有可达对象。 问题在于:当堆被划分为多个区域(代、Region)并且只回收其中一部分时,如何高效地找到从"不回收区域"指向"回收区域"的引用? 以 Young GC 为例:只回收新生代,但老年代中可能持有指向新生代对象的引用。如果不处理这些跨代引用,就会错误地回收仍被老年代引用的新生代对象。最朴素的做法是扫描整个老年代来找出这些引用——但老年代通常远大于新生代,这样做的代价过高,违背了分代收集"只回收一部分堆"的初衷。 卡表(Card Table)和 RSet(Remembered Set)正是为解决这个问题而设计的辅助数据结构。二者的关系并非互相替代,而是层次不同、协作互补:卡表是底层的脏标记机制,RSet 是建立在卡表之上的更高层索引结构。 核心概念速览 在深入细节之前,...
2026-04-19
Java栈帧省略机制详解:为什么异常堆栈会消失?
引言:诡异的异常堆栈消失现象 线上服务报错时,你打开日志准备排查问题,却发现异常堆栈信息神秘消失了: 1java.lang.NullPointerException 只有短短一行异常类名,没有完整的堆栈跟踪。你可能会怀疑:是日志框架出问题了?还是被什么拦截器截断了? 其实,这是 JVM 的一个性能优化机制,叫做 OmitStackTraceInFastThrow(快速抛出时省略堆栈跟踪)。从 JDK 5 开始引入,默认启用。 本文将深入剖析这个机制的设计动机、工作原理、触发条件,以及如何正确应对。 一、问题场景:异常堆栈去哪了? 1.1 复现现象 用一段简单的代码就能复现: 123456789101112public class ExceptionOmitDemo { public static void main(String[] args) { String msg = null; for (int i = 0; i < 500000; i++) { try { ...

2026-01-18
无锁队列
Java 一读一写(SPSC):Memory Barrier + Volatile 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657/** * Single-Producer Single-Consumer (SPSC) 无锁环形队列。 * * <p>原理说明: * - 仅允许一个线程调用 {@code offer()},一个线程调用 {@code poll()}。 * - 由于没有写竞争,无需 CAS;只需保证写操作对消费者可见。 * - 使用两个 volatile 索引(head/tail)建立 happens-before 关系: * 生产者写入元素 → volatile 写 tail → 消费者 volatile 读 tail → 读取元素。 * - 这本质上利用了 Java 内存模型中的“volatile 写-读”内存屏障(StoreLoad), * ...
2021-10-09
JDK 的广泛分支
Oracle Hospot JDK java 8 特定版本以后就不再免费了。 现有的JDK8,2019.1之前的更新都可以免费获取正常使用。 Oracle JDK11是一个长期支持的版本,用于商业环境需要付费。 Azul Zulu builds of OpenJDK Zulu 是Azul公司基于OpenJDK发布的Java SE产品,它没有Oracle JDK对使用场景上的诸多限制,可以放心免费下载和使用。它的核心部分就是原汁原味的OpenJDK,没有任何额外的改动——Azul有时候也会对OpenJDK做bug fix,但这些都是通过提交回到OpenJDK去然后再进入到Zulu Java SE产品中的。它与“自己下载OpenJDK源码,自己build”的最大区别是:Azul会在每次发布Zulu产品之前进行充分的测试,build出来的二进制版本符合Java的兼容性测试;同时,Azul有与Oracle签订合作协议,在critical security fix的方面会比公开发布的OpenJDK源码要更早获得补丁,提前做好build与测试工作,基本上可以跟Oracle在同一时...
2020-03-08
JMX 深度历险
JMX 常见指标 JVM 指标 系统指标 System 相关指标 描述 system.load.average 系统load,如果是docker,此指标收集的物理机的load cpu.system.load.percent 系统所有进程占用cpu的百分比 cpu.jvm.load.percent jvm占用cpu的百分比 system.process.used.phyical.memory 系统使用的物理内存 system.process.used.swap.size 系统使用的swap内存 JVM 内存指标 JVM相关指标 描述 jvm.gc.count GC的次数 jvm.gc.time GC的时间,单位毫秒 jvm.younggc.count 年轻代GC的次数 ,包括的GC算法(Copy,ParNew,PS Scavenge,G1 Young Generation) jvm.younggc.time 年轻代GC的时间,单位毫秒 jvm.fullgc.count 年老代GC的次数,包括的GC算法 jvm.f...
Contents


