Java中FileInputStream本身不会直接导致OOM,真正原因是将大文件一次性读入内存;应采用分块读取(如8KB缓冲区循环读)、BufferedReader按行处理文本、NIO的Channel+ByteBuffer零拷贝等方式控制内存占用。

Java 中 FileInputStream 本身不会直接导致 OOM,真正的问题通常出在**一次性把整个大文件读进内存**(比如用 readAllBytes() 或循环读取但缓存到一个超大 byte[] 或 String 中)。改成“分块读取”核心是控制每次读入内存的数据量,避免堆内存被撑爆。
用固定缓冲区循环读取
这是最基础也最常用的分块方式。不一次性加载全部内容,而是分配一个合理大小的 byte 数组(如 8KB 或 64KB),反复复用它读取、处理、再读取。
- 缓冲区大小建议设为 8192(8KB)或 65536(64KB),兼顾 I/O 效率和内存占用
- 每次
read(buf)返回实际读取字节数,需用该值处理有效数据,不能直接处理整个 buf - 避免把每块数据拼接到一个不断增长的 List
或 StringBuilder 中——这又会 OOM
示例:
try (FileInputStream fis = new FileInputStream("huge.log")) {
byte[] buffer = new byte[8192];
int len;
while ((len = fis.read(buffer)) != -1) {
// 处理 buffer[0] 到 buffer[len-1] 这 len 个字节
processChunk(buffer, 0, len);
}
}
按行读取文本大文件(避免整文件转 String)
如果文件是文本且需按行处理(如日志分析),别用 FileInputStream + String(byte[]),改用 BufferedReader 包装 InputStreamReader,它内部自带缓冲,且每次只 hold 一行内容。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 指定字符集(如 UTF-8),防止乱码
- 行长度不确定时,
BufferedReader的默认缓冲区(8KB)已足够安全 - 不要把所有行存进 ArrayList —— 改为边读边处理(如写入数据库、过滤、统计)
示例:
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("big.txt"), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line); // 单行处理,不累积
}
}
使用 NIO 的 Channel + ByteBuffer 零拷贝(适合高性能场景)
对吞吐量要求高或需要精细控制内存的场景,可用 FileChannel 配合 ByteBuffer,支持直接内存(堆外)或堆内缓冲,还能配合 transferTo/transferFrom 实现零拷贝传输。
-
ByteBuffer.allocateDirect()分配堆外内存,减轻 GC 压力(但需注意清理) - 用
clear()复用 buffer,用limit()和position()控制读写范围 - 读完一块后立即处理或写入目标(如 SocketChannel、另一个文件),别囤积
示例(堆内缓冲):
try (FileChannel channel = FileChannel.open(Paths.get("data.bin"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(65536);
while (channel.read(buffer) != -1) {
buffer.flip(); // 切换为读模式
processBuffer(buffer);
buffer.clear(); // 复用前清空状态
}
}
流式处理 + 及时释放资源
分块只是手段,关键是要让每一块数据“进来 → 处理 → 出去 → 丢弃”,不滞留在内存中。尤其注意:
- 处理逻辑里别意外持有 byte[] 或 String 引用(如加到静态集合、缓存未清理)
- 用 try-with-resources 确保流及时关闭,防止文件句柄和底层资源泄漏
- 若处理结果要暂存,优先写磁盘或数据库,而不是堆内存;必要时用软引用/弱引用+LRU 缓存
不复杂但容易忽略。

















