1. 问题背景与现象分析
最近在排查一个线上服务异常问题时,遇到了一个典型的OOM(OutOfMemoryError)案例。这个案例的特殊之处在于,它不仅导致了内存溢出,还引发了Tomcat服务的假死现象,最终表现为客户端连接被重置(connection reset by peer)。下面我将详细记录整个问题的排查过程和技术细节。
1.1 问题现象描述
我们的Java服务在运行过程中突然出现以下异常现象:
- 服务日志中出现了"Java heap space"的OOM错误
- 虽然内存最终被回收,但服务仍然无法正常响应请求
- 客户端持续收到"connection reset by peer"错误
- Tomcat线程池显示空闲状态,但新连接无法被处理
1.2 初步排查与定位
通过dump内存和日志分析,我们很快定位到问题根源:开发同学在使用easyexcel处理文件上传时,没有实现分页读取,导致大文件一次性加载到内存中,引发了内存溢出。
重要提示:easyexcel官方文档明确建议对大文件进行分片读取,避免一次性加载整个文件到内存中。这是使用此类Excel处理库时必须注意的关键点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 内存溢出与内存泄漏的深入理解
2.1 OOM的常见类型与原因
在Java中,OutOfMemoryError有多种类型,每种类型对应不同的内存区域和问题场景:
| OOM类型 | 触发原因 | 典型场景 |
|---|---|---|
| Java heap space | 堆内存不足 | 大对象分配、内存泄漏 |
| GC Overhead limit exceeded | GC效率过低 | 内存不足、内存泄漏 |
| Metaspace | 元空间不足 | 动态类加载过多 |
| Direct buffer memory | 直接内存不足 | NIO使用不当 |
| Unable to create new native thread | 线程数超限 | ulimit设置不当 |
| Requested array size exceeds VM limit | 数组过大 | 超大数组分配 |
| CodeCache | JIT缓存溢出 | JIT缓存设置过小 |
