程序员必备的十大技能(进阶版)之性能调优与故障排查(二)

简介: 教程来源 qfcrz.cn 本节系统梳理Java内存问题排查全流程:涵盖JVM内存结构(堆、元空间、直接内存等)、四大典型泄漏场景(静态集合、ThreadLocal、监听器、动态代理)、jstat/jmap/jcmd/Arthas等实战工具用法、MAT深度分析技巧(Dominator Tree、OQL查询),以及GC调优策略与I/O问题定位方法。

三、内存问题排查

3.1 内存问题分类
image.png
3.2 JVM内存结构回顾

┌─────────────────────────────────────────────────────────────┐
│                      JVM 运行时数据区                        │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────┐   │
│  │                       堆                             │   │
│  │  ┌───────────┐  ┌───────────┐  ┌───────────┐       │   │
│  │  │  新生代    │  │  老年代    │  │  元空间    │       │   │
│  │  │ Eden/S0/S1│  │   Old     │  │  Metaspace│       │   │
│  │  └───────────┘  └───────────┘  └───────────┘       │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │ 虚拟机栈     │  │ 本地方法栈  │  │ 程序计数器  │         │
│  │ (线程私有)  │  │ (线程私有) │  │ (线程私有) │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    直接内存(DirectBuffer)            │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

3.3 内存泄漏典型案例

// 案例1:静态集合持有对象引用
public class StaticListLeak {
    private static List<byte[]> list = new ArrayList<>();

    public void addData() {
        // 不断添加,永远不清理
        list.add(new byte[1024 * 1024]); // 1MB
    }
    // 解决方法:使用WeakHashMap或配置缓存淘汰策略
}

// 案例2:ThreadLocal未remove
public class ThreadLocalLeak {
    private static final ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();

    public void process() {
        threadLocal.set(new byte[10 * 1024 * 1024]); // 10MB
        // 业务处理...
        // 忘记remove!
    }
    // 线程池中的线程复用,导致内存泄漏
    // 解决方法:finally块中调用threadLocal.remove()
}

// 案例3:监听器/回调未注销
public class ListenerLeak {
    private List<EventListener> listeners = new ArrayList<>();

    public void register(EventListener listener) {
        listeners.add(listener); // 注册后忘记注销
    }
    // 解决方法:使用WeakReference或提供unregister方法
}

// 案例4:动态代理导致的类加载器泄漏
// 解决方法:使用非持久化的类加载器或控制代理生成数量

3.4 内存问题排查工具实战

# 1. 查看堆内存使用情况
jstat -gc <PID> 1000 10

# 输出字段说明:
# S0C/S1C: Survivor0/1容量
# S0U/S1U: Survivor0/1使用量
# EC/EU: Eden容量/使用量
# OC/OU: 老年代容量/使用量
# MC/MU: 元空间容量/使用量
# YGC/YGCT: Young GC次数/总时间
# FGC/FGCT: Full GC次数/总时间
# GCT: GC总时间

# 2. 生成堆转储文件(dump)
jmap -dump:live,format=b,file=heap.hprof <PID>

# 3. 实时分析堆对象
jmap -histo:live <PID> | head -20

# 4. 使用jcmd(JDK 8+推荐)
jcmd <PID> GC.heap_info
jcmd <PID> GC.class_histogram
jcmd <PID> VM.native_memory

# 5. 使用Arthas分析
# 查看JVM内存分布
memory

# 查看堆对象统计
heapdump --live /tmp/heap.hprof

# 查看最占内存的对象
ognl '@com.alibaba.arthas.deps.org.apache.commons.lang3.ArrayUtils@toString(new java.util.ArrayList())'

3.5 堆内存分析(MAT/Eclipse MAT)

// MAT 使用技巧
// 1. 打开heap.hprof文件
// 2. 查看Leak Suspects Report(泄漏嫌疑报告)
// 3. 使用Histogram查看所有类的实例数
// 4. 使用Dominator Tree找出占用内存最大的对象
// 5. 使用OQL(对象查询语言)执行自定义查询

// OQL示例:查询所有byte数组
SELECT * FROM "[B"

// 查询特定类的实例
SELECT toString(s) FROM com.example.entity.Order s WHERE s.orderId.startsWith("TEST")

// 查看某个对象的GC Root路径
// 右键对象 → Merge Shortest Paths to GC Roots → exclude weak/soft references

3.6 GC调优实战

GC选择指南:
  内存 < 4GB: -XX:+UseSerialGC
  内存 4-8GB, 低延迟要求: -XX:+UseG1GC
  内存 > 8GB, 吞吐量优先: -XX:+UseParallelGC
  低延迟极端要求(<10ms): 使用ZGC或ShenandoahGC

G1GC调优参数:
  -XX:G1HeapRegionSize=16m              # Region大小
  -XX:MaxGCPauseMillis=200              # 目标暂停时间
  -XX:G1NewSizePercent=5                # 新生代初始比例
  -XX:G1HeapWastePercent=5              # 允许浪费比例
  -XX:ConcGCThreads=4                   # 并发GC线程数
  -XX:ParallelGCThreads=8               # 并行GC线程数
  -XX:InitiatingHeapOccupancyPercent=45 # MixedGC触发阈值

# 查看GC日志
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log

# GC日志分析工具
# GCeasy (https://gceasy.io)
# GCViewer

四、I/O问题排查

4.1 磁盘I/O问题

# 1. 查看磁盘I/O整体情况
iostat -x 1

# 关键指标:
# %util: 磁盘利用率(超过80%说明繁忙)
# await: 平均I/O等待时间(超过10ms说明慢)
# r/s, w/s: 每秒读写次数
# rkB/s, wkB/s: 每秒读写KB数
# avgqu-sz: 平均队列长度

# 2. 查看哪些进程在读写磁盘
iotop -o

# 3. 查看具体文件I/O(需要root)
lsof | grep deleted  # 查看被删除但仍被进程占用的文件

# 4. 慢SQL导致的磁盘I/O问题
# 查看MySQL慢查询日志
# 使用Percona Toolkit的pt-query-digest分析

4.2 文件描述符耗尽

# 查看进程打开的文件描述符数量
lsof -p <PID> | wc -l

# 查看进程限制
cat /proc/<PID>/limits

# 查看系统级别限制
ulimit -n
# 临时修改
ulimit -n 65535

# 永久修改 /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

# 常见原因:
# 1. 连接池未关闭
# 2. 文件流未关闭
# 3. 临时文件未清理
// 文件流未关闭典型案例
public class FileLeak {
    public void readFile(String path) {
        try {
            InputStream is = new FileInputStream(path);
            // 业务处理
            // 忘记在finally中关闭
        } catch (IOException e) {
            // 异常处理
        }
    }

    // 正确写法
    public void readFileCorrect(String path) {
        try (InputStream is = new FileInputStream(path)) {
            // 业务处理
        } catch (IOException e) {
            // 异常处理
        }
    }
}

来源:
https://dffne.cn/

相关文章
|
2月前
|
运维 Java 测试技术
程序员必备的十大技能(进阶版)之性能调优与故障排查(四)
教程来源 https://aescc.cn/ 本节系统介绍Java应用性能分析与稳定性保障核心实践:涵盖Arthas诊断、火焰图性能剖析、全链路压测方法论及JMeter实战、混沌工程故障注入(ChaosBlade),并复盘Full GC与数据库死锁两大典型故障案例,助力高效定位与解决线上性能问题。
|
2月前
|
自然语言处理 监控 数据可视化
大模型应用:MiniLM实战案例:基于MiniLM模型的多语言智能客服问答检索系统.124
本项目构建基于深度语义理解的智能客服原型系统,支持中英日多语言混合输入与跨语言语义对齐;采用Sentence Transformer向量化+余弦相似度检索,实现口语化、同义表述精准匹配;集成PCA/t-SNE可视化、知识库热力图及性能监控,确保毫秒级响应与可解释性。
246 7
|
2月前
|
存储 Java 测试技术
Java 软件测试(一)核心概念与实例一览
Java 软件测试(一)核心概念与实例一览
130 0
|
2月前
|
设计模式 安全 程序员
程序员进阶工程师必备技能之性能、稳定性与安全优化(二)
教程来源 https://unbgv.cn/ 本文系统介绍稳定性保障核心实践:涵盖SLA指标定义、超时重试与断路器容错、令牌桶限流与服务降级、幂等性设计,以及基于混沌工程的故障演练方法,全面提升系统可靠性与韧性。
|
2月前
|
运维 Java 程序员
程序员必备的十大技能(进阶版)之性能调优与故障排查(一)
教程来源 https://qeext.cn/ 本文系统讲解性能调优与故障排查核心技能,涵盖故障方法论、CPU/内存/I/O/网络/数据库问题定位、Java诊断工具(Arthas/JVM)、全链路压测及混沌工程,辅以实战案例与黄金排查原则,助开发者从“重启党”进阶为问题终结者。
|
2月前
|
运维 监控 程序员
程序员必备的十大技能(进阶版)之性能调优与故障排查(三)
教程来源 https://bgnno.cn/ 本节系统讲解网络与数据库性能问题排查:涵盖TCP连接状态分析、TIME_WAIT优化、延迟诊断、连接池配置;以及慢查询定位、索引失效识别、事务锁监控和连接池调优,助力高效定位并解决生产环境常见瓶颈。
|
2月前
|
设计模式 架构师 程序员
程序员必备的十大技能(进阶版)之设计模式与架构思维(五)
教程来源 https://xgmoi.cn/ DDD是应对复杂业务的架构方法论,含战略设计(限界上下文、上下文映射、子域划分)与战术设计(实体、值对象、聚合根、领域服务等),强调以领域模型驱动开发,实现业务与技术深度对齐。
|
2月前
|
设计模式 程序员
程序员必备的十大技能(进阶版)之设计模式与架构思维(二)
教程来源 https://vrhyh.cn/ 结构型模式关注类与对象的组合组织,提升系统灵活性与可维护性。含适配器(兼容接口)、装饰器(动态增强)、代理(控制访问)、外观(简化子系统)、组合(树形结构)五种核心模式,均通过封装、委托与抽象实现松耦合设计。
|
2月前
|
存储 Cloud Native 程序员
程序员必备的十大技能(进阶版)之云原生与容器化(一)
教程来源 https://oplhc.cn/ 云原生已成现代应用架构标准范式,本文系统解析容器原理、Docker实践、Kubernetes编排、服务网格、GitOps等核心技术,覆盖从虚拟化演进到可观测性建设的十大维度,助力开发者全面掌握云原生技术体系。
|
2月前
|
设计模式 网络协议 Java
程序员必备的十大技能(进阶版)之网络与高并发原理(一)
教程来源 http://yyvgt.cn/ 本文深度解析网络与高并发核心原理,涵盖TCP/IP协议栈、三次握手/四次挥手、滑动窗口、拥塞控制、五种I/O模型(含epoll机制)、零拷贝、Reactor/Proactor、Java NIO/Netty源码及全链路调优,助你突破性能瓶颈,成为高阶工程师。

热门文章

最新文章