ByteBuffer.clear() 重置position为0、limit为capacity,并不清除数据;适用于已处理完全部数据的场景,而半包应使用compact()保留未读字节。

ByteBuffer.clear() 并不真正“清空”数据,而是重置读写位置,为下一轮流式读写做好准备。 它是实现循环缓冲(如网络收发、日志批量写入、传感器数据流处理)的关键操作,但必须配合正确的读写模式切换和边界判断,否则容易读到旧数据或越界。
理解 clear() 的真实行为:重置指针,不是擦除内存
调用 clear() 会将 position 设为 0,limit 设为 capacity,mark 清除。缓冲区底层字节数组中的内容**完全不变**——只是告诉后续的 put() 从头开始写,get() 从头开始读。
- 适合场景:固定大小缓冲区反复用于接收不定长消息(如 TCP 粘包拆包)、循环采集写入环形日志等
- 错误认知:“clear 后数据就安全了” → 实际上未覆盖的数据仍存在,若读逻辑有缺陷,可能误读历史残留
典型流式循环读写流程(以网络接收为例)
假设用一个 1024 字节的 ByteBuffer 接收 TCP 数据流,需持续解析多个变长协议包:
-
接收阶段:调用
channel.read(buffer),数据追加到buffer.position()之后;读完后调用buffer.flip()准备读取 -
解析阶段:用
get()或getXXX()按协议提取字段;每成功解析一个完整包,用buffer.compact()将未读完的剩余字节移到开头(保留未解析部分) -
重用阶段:当
compact()后剩余空间足够,直接继续read();若缓冲区已满且无剩余数据,则调用clear()彻底回到初始状态,等待新一批数据
clear() 和 compact() 的选择逻辑
二者都为重用缓冲区服务,但适用时机不同:
-
clear():适用于「当前缓冲区所有数据已处理完毕」,可安全丢弃全部内容,从头开始接收 -
compact():适用于「还有部分数据未解析完(比如半包)」,需保留尾部未读字节,并把它们移到开头,腾出后面空间继续接收 - 常见错误:收到半包后误用
clear(),导致未解析的半包被覆盖,造成协议解析失败
实际代码片段示意(简化版)
// 初始化ByteBuffer buffer = ByteBuffer.allocate(1024);
// 循环接收while (connected) { int n = channel.read(buffer); if (n > 0) { buffer.flip(); while (hasCompletePacket(buffer)) { processPacket(buffer); // 解析并消费一个包 } buffer.compact(); // 保留未读部分 } else if (n == 0) { // 无新数据,可跳过或稍作等待 } else { // 连接关闭或异常 break; }}










