一、报错信息
Java 程序中 , 设置 无限循环 , 每次循环 休眠 10 秒后 , 再执行程序逻辑 , 在命令行中打印日志信息 ;
for (;;) {
try {
// 休眠 10 秒钟
Thread.sleep(10000);
// 程序逻辑
System.out.println("日志内容");
} catch (Exception e) {
e.printStackTrace();
}
}
上述程序 运行了 2 天后 , 突然出现了 循环暂停情况 , 连续暂停了 几十分钟 到 数个小时 , 此时 在 命令行敲一下回车 , 程序再次恢复运行 ;
期间打印了大量的日志信息 , 大约有 30MB 左右 ;
二、问题分析
1、Windows 命令行的缓冲区机制
在 Windows 的 Cmd 或 PowerShell 中 , 默认的 屏幕缓冲区 大小有限 , 如果 程序输出的日志超过 缓冲区容量 , 后续的 System.out.println() 操作会被阻塞 , 直到缓冲区腾出空间 ;
设置 保留的历史缓冲区数量 , 若 开启 " 丢弃旧的副本 ( Discard Old Duplicates ) " 选项 , 当 缓冲区满时 会自动丢弃旧数据 , 避免阻塞 , 如果未开启该选项 , 则 缓冲区满后写入操作会挂起 ;
当 用户在 命令行窗口 敲击回车时 , 会强制刷新缓冲区 , 释放被阻塞的输出操作 , 程序得以继续运行 , 但是日志再输出一些 , 几小时内又会立刻写满 ;
2、命令记录设置
Windows 命令提示符中的 命令记录 设置 的 缓冲区大小、缓冲区数量 和 丢弃旧的副本 是控制命令行历史记录与显示的关键设置 , 如下图所示 :
缓冲区大小 ( Buffer Size ) 指 命令行窗口的 屏幕缓冲区 大小 , 即能够存储的历史输出行数 ;
缓冲区大小 默认值为 50 , 表示最多保存 50 行历史记录 , 若输出内容超过此限制 , 旧内容会被 覆盖或丢弃 , 取决于 " 丢弃旧的副本 " 选项设置 ;
缓冲区大小 设置为 更大值 可避免长文本被截断 , 完整查看大量输出内容 ;
缓冲区数量 ( Buffer Amount ) 是 存储的历史命令数量 , 用于控制历史记录的存储容量 ;
丢弃旧的副本 ( Discard Old Duplicates ) 选项 用于 控制 超出缓冲区容量 时是否保留旧数据 ;
- 启用 : 当输出内容超出缓冲区大小时 , 自动丢弃 最旧的内容 ;
- 禁用 : 保留缓冲区内的所有内容 , 但新内容可能无法显示 , 需手动滚动查看 ;
- 适用场景 : 需长期监控大量输出时建议禁用 , 日常使用可启用以减少内存占用 ;
三、解决方案
1、设置 " 命令记录 " 选项
右键点击 命令提示符 标题 , 在弹出的菜单中 , 点击 " 属性 " 选项 ;
在 " 命令提示符 " 属性 对话框 的 选项 面板中 , 设置 命令记录 选项 ,
设置 缓冲区大小 999 , 缓冲区数量 999 , 勾选 " 丢弃旧的副本 " 选项 ;
2、将日志重定向到文件
通过命令行启动程序时 , 将 命令行输出 重定向到文件 ;
java Main > log.txt 2>&1
上述命令 可以 将 Java 程序 Main 的标准输出和标准错误全部重定向到文件 log.txt 中 ;