推荐日志缓冲区大小为8kb–16kb,需根据写入频率和单条日志长度权衡;必须显式flush关键日志,避免嵌套缓冲或流复用不当。

直接用 FileOutputStream 写日志,不加缓冲,每次 write() 都可能触发一次磁盘写入,性能极差。真正有效的做法是套一层 BufferedOutputStream,并合理设置缓冲区大小——不是越大越好,也不是默认就最优。
缓冲区大小怎么选才合适
日志场景有其特殊性:写入频繁、单次数据量小、但总量可能很大。缓冲区太小(如1KB),起不到合并写入的作用;太大(如128KB),可能造成日志延迟落盘,影响排查时效性。
- 推荐值:8KB–16KB(即 8192–16384 字节),这是多数日志场景的平衡点
- 若日志写入非常密集(如每秒数百条),可压到 8KB,降低内存占用和 flush 延迟
- 若单条日志较长(如含堆栈、JSON结构),且允许少量延迟,可设为 16KB
- 避免用默认构造(
new BufferedOutputStream(fos)),它虽也是8KB,但显式指定更清晰、可维护
必须显式调用 flush() 的关键节点
日志不是普通文件——你往往需要“写完立刻可见”。仅靠 close() 触发 flush 是危险的,因为日志流通常长期存活,不会频繁关闭。
- 每次写完一条关键日志(如 ERROR 级别)后,立即
flush() - 在定时任务中定期
flush()(如每5秒一次),防止缓冲区积压 - 不要依赖
try-with-resources自动 close 来刷盘,除非是短生命周期的日志批次
避开几个常见陷阱
很多日志性能问题其实来自误用,而非缓冲区本身。
- 不要对同一个
FileOutputStream多次包装BufferedOutputStream,会造成嵌套缓冲,逻辑混乱 - 避免混用字节流和字符流缓冲:比如用
BufferedWriter写文本日志时,底层已自带缓冲,再套BufferedOutputStream是冗余的 - 不要在循环内反复 new 流对象,缓冲区初始化也有开销;应复用流实例,只在必要时重建
- 追加模式(
new FileOutputStream("log.txt", true))不影响缓冲配置,但要注意多线程写入需额外同步
一个简洁可用的示例
以下是一个轻量、可控的日志输出器片段:
private final BufferedOutputStream logStream;
public LogWriter(String filePath) throws IOException {
FileOutputStream fos = new FileOutputStream(filePath, true); // 追加
this.logStream = new BufferedOutputStream(fos, 8192); // 显式设为8KB
}
public void writeLine(String line) throws IOException {
logStream.write(line.getBytes(StandardCharsets.UTF_8));
logStream.write('\n');
logStream.flush(); // 每行都刷盘,确保实时性
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











