clear()重置指针准备全量覆写,position=0、limit=capacity;compact()保留未读数据并前移,position设为未读长度、limit=capacity,适用于粘包续写场景。

Java NIO 中的 clear() 和 compact() 都是用来重置 ByteBuffer(或其他 Buffer 子类)以便再次写入,但它们行为不同、适用场景也不同。选错方法容易导致数据丢失或逻辑混乱。
clear():彻底重置,适合“旧数据已全部处理完”
调用 clear() 后,Buffer 立即恢复为可写状态:
- position 设为 0
- limit 设为 capacity
- mark 被清除(设为 -1)
- 底层数组内容不变,但所有指针都回到起始位置
它相当于“擦掉读写标记”,不关心 buffer 里原来有没有未读数据。所以只应在确认所有数据已处理完毕(比如已解析、已转发、已落盘)后使用。例如:
从 SocketChannel 读取一整包 HTTP 请求并完整解析后,准备下一次接收新请求,就该调用 buffer.clear()。
立即学习“Java免费学习笔记(深入)”;
compact():保留未读数据,适合“还有残留字节要接着用”
当 position < limit(即仍有未读数据),又想继续往 buffer 写入新内容时,compact() 是唯一安全选择:
- 把
[position, limit)区间的未读字节,整体复制到 buffer 开头(索引 0 起) - position 更新为原未读数据长度(即复制后的末尾位置)
- limit 设为 capacity
- mark 被清除
典型场景是网络粘包/半包处理:一次 read() 只读到半个消息,解析完包头发现包体不全,这时不能丢掉那半个包——得调用 compact() 把残留数据挪到前面,腾出后面空间等下次 read() 继续填。
怎么判断该用哪个?看 position 和 limit 的关系
读操作完成后(比如调用过 flip() 并完成 get() 或 array() 处理),检查当前状态:
- 如果
position == limit→ 所有数据已读完 → 用clear() - 如果
position < limit→ 还有字节没读 → 必须用compact()
注意:compact() 前必须确保已完成对已读部分的处理;否则未推进的 position 会让 compact 移走本该保留的数据。
常见误区提醒
以下做法容易出问题:
- 在还有未读数据时调用
clear()→ 后续写入会覆盖残留数据,造成协议解析失败 - 在未完成读操作(如没调用
get()或未手动推进position)就调用compact()→ 把“未读”误当作“已读”移走 - 调用
compact()后又调用flip()→ 多余且错误,compact 后 buffer 已处于可写状态,直接write()即可 - 频繁 compact 大缓冲区 → 触发数组复制开销,可考虑换用 Netty 的
CompositeByteBuf或动态扩容策略


















