引言

在Java开发中,开发者常会遇到各种"诡异"问题,本文总结了高频问题场景、分析思路和解决方案,助你快速定位问题根源。

一、内存泄漏:对象为何无法被回收?

现象

应用运行时间越长,内存占用持续增长Full GC频繁但回收效果差最终触发OutOfMemoryError: Java heap space

排查步骤

生成Heap Dumpjmap -dump:format=b,file=heap.hprof

使用MAT工具分析

查看Dominator Tree找到占用最大的对象检查Path to GC Roots找到意外存活的对象引用链

典型案例

// 静态集合未清理导致内存泄漏

public class CacheManager {

private static List cache = new ArrayList<>();

public static void add(Object obj) {

cache.add(obj);

}

}

解决方案:改用WeakHashMap或定期清理策略

二、线程死锁:应用卡死无响应

快速定位

获取线程快照

bash

jstack > thread_dump.log

搜索deadlock关键词

Found one Java-level deadlock: =============================

"Thread-1":

waiting to lock monitor 0x00007f... (object 0x000000076ab...),

which is held by "Thread-0"

示例代码

java // 错误的锁顺序导致死锁

public void transfer(Account from, Account to, int amount) {

synchronized(from) {

synchronized(to) {

// 转账操作... } } }

解决方案:

统一加锁顺序(如按账户ID排序)

三、数据库连接池耗尽

现象

出现Cannot get a connection, pool error数据库活跃连接数达到最大值

排查方向

检查连接泄漏

确认所有Connection都在finally块中关闭使用Druid连接池的removeAbandoned机制

监控连接池指标DataSource ds = ...;

DruidDataSource dds = (DruidDataSource) ds;

System.out.println("Active:" + dds.getActiveCount());

四、NPE攻击:空指针异常

防御性编程技巧

使用Objects工具类Objects.requireNonNull(param, "参数不能为空");

Optional优雅处理Optional.ofNullable(user)

.map(User::getAddress)

.map(Address::getCity)

.orElse("未知");

@NonNull注解public void process(@NonNull String input) {

// 方法体

}

五、CPU飙升100%问题

排查流程

定位高CPU线程top -Hp # 查看线程CPU占用

printf "%x\n" # 转换线程ID为十六进制

分析线程栈

在jstack结果中搜索nid=0x<十六进制tid>常见原因:死循环、频繁GC、锁竞争

六、Full GC频繁

关键指标分析

GC日志配置-XX:+PrintGCDetails -Xloggc:/path/to/gc.log

排查方向

年轻代过小导致对象过早进入老年代内存泄漏(见第一部分)大对象分配(检查byte[]、大集合)

七、ClassNotFoundException vs NoClassDefFoundError

差异对比

场景触发时机常见原因ClassNotFoundException类加载器主动查找类时失败依赖缺失/Jar包未部署NoClassDefFoundErrorJVM已经加载过类,但无法找到定义静态初始化失败/类文件被篡改

八、分布式锁失效场景

经典问题复现

// Redis分布式锁错误用法

Boolean result = redis.setnx(key, value);

if(result) {

// 业务处理...

redis.expire(key, timeout); // 非原子操作!

}

风险:setnx与expire非原子操作,进程崩溃导致死锁

解决方案:使用Redisson或Lua脚本保证原子性

九、日志排查技巧

快速定位异常

按时间范围过滤grep "2023-07-20 14:" app.log

异常链追踪awk '/Exception/,/^\s*at /' app.log

Arthas实时追踪trace com.example.Service * '#cost > 100'

十、网络调优必知

关键参数

// TCP参数优化

-Djava.net.preferIPv4Stack=true // 避免IPv6问题

// 连接超时设置

HttpClientBuilder.create()

.setDefaultRequestConfig(RequestConfig.custom()

.setConnectTimeout(5000)

.setSocketTimeout(15000).build());

总结

掌握以下核心技能可解决90%问题:

工具链:jstack/jmap/Arthas/MAT监控体系:Prometheus+Grafana+JMX编码规范:防御性编程+资源管理

TIP:复杂问题可使用-XX:+HeapDumpOnOutOfMemoryError让JVM自动生成Dump文件

这篇文章结构清晰、覆盖高频问题,且包含可直接操作的代码片段和命令,适合开发者收藏作为排查手册。如需扩展某个场景的细节,欢迎留言讨论!

Previous Post 微信朋友圈怎么发纯文字[多图]