memoryhandler 是 java 日志的兜底容错组件,非通用内存缓冲器;它仅在下级 handler 失败或显式 push() 时批量转发日志,需手动 sethandler() 并合理配置 pushlevel 与缓冲大小。

MemoryHandler 是什么,它真能“缓存日志到内存”?
MemoryHandler 是 java.util.logging 里一个真实存在的 Handler,但它**不是通用内存缓冲器**——它只在特定条件下把日志“暂存”进内存数组,等触发条件(比如下级 Handler 报错、或显式 push())才批量转发。它的核心设计目标是:**兜底容错,不是性能优化**。误当成 BufferedWriter 那种流式缓冲用,大概率会丢日志。
为什么 new MemoryHandler() 后日志完全不输出?
这是最常见踩坑点:MemoryHandler 默认构造函数不绑定任何下级 Handler,且自身不写文件、不打控制台。它只是个“中转站”,必须手动 setHandler() 才能生效。
- 必须显式传入一个实际工作的
Handler(如FileHandler或ConsoleHandler)给setHandler() - 默认
pushLevel是Level.SEVERE,意味着只有 SEVERE 级别日志才会触发“推送”动作;INFO/WARN 日志只会堆积在内存环形缓冲区里,不主动刷出 - 缓冲区满后,默认行为是丢弃最早日志(
push()不自动触发),不是抛异常
如何正确配置 MemoryHandler 实现“异常时补发最近日志”?
这才是它的典型用途:当前端 Handler(比如网络日志服务)临时失败时,把最近几条日志先存内存,等恢复后再补发。关键在控制 push() 时机和缓冲策略。
- 用
new MemoryHandler(new FileHandler("fallback.log"), 100, Level.ALL)指定后备 Handler 和缓冲大小 - 重写
publish()方法,在捕获下级 Handler 异常时调用super.push(),强制刷出内存日志 - 注意
size参数是环形缓冲区长度,不是字节数;设太小(如 10)可能刚记下 ERROR 就被 INFO 覆盖掉 - 别依赖
close()自动 push —— 它只关闭下级 Handler,不刷内存缓冲区
和 Log4j2 的 RingBufferAppender 或 SLF4J + Logback 的 AsyncAppender 有可比性吗?
没有。这不是同类工具:MemoryHandler 是同步、阻塞、无并发保护的简单数组封装;而 RingBuffer/AsyncAppender 是为高吞吐设计的无锁队列+异步线程模型。
立即学习“Java免费学习笔记(深入)”;
-
MemoryHandler在多线程高频打日志时,publish()本身不加锁,依赖上层Logger的同步机制,但缓冲区操作仍可能因竞争导致丢失或覆盖 - 它不支持自定义序列化、无批量 flush 控制、不能设置超时或重试逻辑
- 如果项目已用 Log4j2 或 Logback,强行套用
MemoryHandler只会增加维护成本,不如直接用它们原生的故障转移机制(如FailoverAppender)











