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

简介: 教程来源 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/

相关文章
|
8天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
2967 7
|
10天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3068 20
|
23天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23567 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
4天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
1953 3
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
10天前
|
人工智能 JSON BI
DeepSeek V4-Pro 接入 Claude Code 完全实战:体验、测试与关键避坑指南
Claude Code 作为当前主流的 AI 编程辅助工具,凭借强大的代码理解、工程执行与自动化能力深受开发者喜爱,但原生模型的使用成本相对较高。为了在保持能力的同时进一步降低开销,不少开发者开始寻找兼容度高、价格更友好的替代模型。DeepSeek V4 系列的发布带来了新的选择,该系列包含 V4-Pro 与 V4-Flash 两款模型,并提供了与 Anthropic 完全兼容的 API 接口,理论上只需简单修改配置,即可让 Claude Code 无缝切换为 DeepSeek 引擎。
2460 3
|
8天前
|
人工智能 安全 开发工具
Claude Code 官方工作原理与使用指南
Claude Code 不是传统代码补全工具,而是 Anthropic 推出的终端 AI 代理,具备代理循环、双驱动架构(模型+工具)、全局项目感知、6 种权限模式等核心能力,本文基于官方文档系统解析其工作原理与高效使用技巧。
1339 0
|
8天前
|
存储 Linux iOS开发
【2026最新】MarkText中文版Markdown编辑器使用图解(附安装包)
MarkText是一款免费开源、跨平台的Markdown编辑器,主打所见即所得实时预览,支持Windows/macOS/Linux。内置数学公式、流程图、代码高亮、多主题及PDF/HTML导出,是Typora的轻量免费替代首选。(239字)