引言
在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
public static void add(Object obj) {
cache.add(obj);
}
}
解决方案:改用WeakHashMap或定期清理策略
二、线程死锁:应用卡死无响应
快速定位
获取线程快照
bash
jstack
搜索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
printf "%x\n"
分析线程栈
在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文件
这篇文章结构清晰、覆盖高频问题,且包含可直接操作的代码片段和命令,适合开发者收藏作为排查手册。如需扩展某个场景的细节,欢迎留言讨论!