ByteBuffer.clear()并未真正清空数据,仅将position设为0、limit设为capacity、mark设为-1,使缓冲区进入可写状态,但原数据仍保留在底层数组中。

ByteBuffer.clear() 真的“清空”了数据吗?
clear() 不会擦除底层字节数组里的内容,它只重置三个关键指针:position 设为 0,limit 设为 capacity,mark 清除(设为 -1)。这表示缓冲区已准备好接收新写入——但旧数据仍在内存里,只是被标记为“可覆盖”。如果你误以为调用后数据已安全销毁,可能在后续 flip() 或 get() 时读到残留值。
什么时候该用 clear(),而不是 compact() 或 rewind()?
适用于明确要**丢弃全部已有内容、从头开始写入**的场景,比如网络 IO 中处理下一个请求包、日志批量写入前重用缓冲区。注意以下区别:
-
clear():重置为“全空可写”状态,适合完全重写 -
compact():把未读数据移到开头,position指向其后,适合“部分读取后继续写入” -
rewind():只重置position = 0,limit不变,适合重读已写入内容
clear() 后直接 get() 会抛出 BufferUnderflowException?
会。因为 clear() 后 limit == capacity,而 position == 0,此时缓冲区处于“可写不可读”状态。若立即调用 get() 或 array() 配合 position/limit 手动读取,会因 position >= limit 失败。正确流程是:
- 写入数据 → 调用
flip()(limit = position,position = 0)→ 读取 - 读完再写入 → 必须先
clear()(或compact()),不能只rewind()
常见错误示例:buffer.clear(); buffer.get(); —— 这行 get() 必然抛 BufferUnderflowException。
clear() 对堆内/堆外缓冲区有性能差异吗?
没有。无论 ByteBuffer.allocate() 还是 ByteBuffer.allocateDirect(),clear() 都只是整数字段赋值,开销恒定 O(1)。但要注意:堆外缓冲区(DirectByteBuffer)的 clear() 不触发 GC 或内存释放,它和堆内一样,只改指针。真正影响性能的是后续写入模式——如果频繁 clear() 后只写少量字节,可能造成 limit 远大于实际有效数据,导致 flip() 后读取范围过大,甚至越界解析。
容易被忽略的一点:如果自定义了 slice() 或 duplicate() 出子缓冲区,父缓冲区调用 clear() 不会影响子缓冲区的 position 和 limit,但它们共享底层数组——这意味着子缓冲区仍可能读到你认为“已清空”的旧数据。

















