BufferOverflowException是NIO缓冲区写入越界异常,非内存溢出;其本质是put()时position+写入字节数>limit即刻抛出,判断依据为remaining()(=limit-position),而非capacity()。

BufferOverflowException 不是内存溢出,而是 NIO 缓冲区写入越界时的即时校验失败。它在调用 put() 时检查 position + 写入字节数 > limit,一旦为真就立刻抛出——不等数据真正填满 capacity,也不依赖 JVM 堆状态。
真正决定能否写的,是 remaining(),不是 capacity()
capacity() 是缓冲区总大小,固定不变;remaining() = limit - position,才是当前可安全写入的字节数。常见误判是:分配了 1MB 缓冲区,就以为“没超 1MB 就安全”,却忽略 flip() 后 limit 被设为之前写入长度,position 归零,此时 remaining() 可能只剩 0。
- 写入前必须用
buffer.remaining() >= data.length判断,而非data.length - 字符串转 byte[] 时,用
str.getBytes(StandardCharsets.UTF_8).length算真实字节长,避免按 charCount 分配导致中文场景溢出 - 批量写入推荐
buffer.put(src, offset, length),并确保length不超过buffer.remaining()
写入流程中三个关键方法的真实作用
flip()、compact()、clear() 都不扩容,只重置 position 和 limit。错用会直接让 remaining() 归零,下一次 put 必崩。
-
flip():写完后切读模式 ——
limit = position; position = 0。之后若还要写,必须先 compact() 或 clear() -
compact():保留未读数据,挪到开头,
position = 已读字节数;limit = capacity。适合边读边写流式场景 -
clear():彻底重置,
position = 0;limit = capacity。适合丢弃全部旧数据、完全重用缓冲区
变量长度数据必须分片写入
NIO 缓冲区不会自动扩容。哪怕你 allocate(1MB),遇到 5MB 数据也得手动拆包。不拆的后果不是性能下降,而是第一次 put() 就抛异常。
- 用
buffer.hasRemaining()控制循环,比硬算长度更安全 - 网络或文件读取中,把大块数据按
Math.min(src.length, buffer.remaining())分段写入 - 避免在循环内反复调用 flip() 后直接 put() —— 此时 position == limit,remaining() 恒为 0
这个异常本质是 API 层面的边界防护,触发快、定位准。守住 remaining() 判断、理清三个元数据操作的语义、对变长数据做分片,就能稳住写入逻辑。


















