Bytes
这一部分是本卷的重点,讲共享主线:一个只读的 Bytes 怎么做到 clone、切片、drop 都不拷贝数据。代码几乎都在 src/bytes.rs,1.7k 行,再加上 src/bytes_mut.rs 末尾给 freeze 用的一张表。
四章按「先看结构,再看每种存储,再看 clone 和切片」排列:
- 结构与 Vtable:
Bytes是ptr、len、data、vtable四个字,32 字节;Vtable是五个函数指针,clone和is_unique借用data,into_vec、into_mut、drop从 1.12.0 起按值拿data(#826)。用手写表而不是 trait object,是因为data可以是空指针、带标记的指针或缓冲本身的地址,还要能被原子地换掉。 - 五种存储:静态切片、可提升(奇偶两张表)、
Shared、from_owner的Owned<T>、BytesMut冻结出来的共享块,各自的 clone /into_vec/into_mut/is_unique/ drop;From<Vec<u8>>在len == cap时走Box<[u8]>不分配,否则直接建Shared;用一个程序认出每种构造最后落在哪张表上。 - clone 与提升:可提升存储第一次 clone 时用 CAS 把
data换成Shared,竞争失败的一方释放自己的那份;引用计数的内存序;is_unique与try_into_mut。 - 切片:
slice、split_to、split_off先 clone 一次再改ptr和len;truncate遇到可提升存储要先提升,因为那两张表不记容量;切出空段时不 clone,返回一个地址仍在原处的静态空Bytes。
flowchart TB ctor["构造 Bytes"] --> pick["选一张 vtable"] pick --> clonenode["clone:按表分派"] clonenode --> promote["第一次 clone 提升"] pick --> slicenode["slice:改 ptr 和 len"] slicenode --> clonenode clonenode --> dropnode["drop:按表分派"] pick --> back["转回 Vec 或 BytesMut"]
谁在用这些 Bytes:hyper 把请求头和 body 分块从读缓冲里 split_to(n).freeze() 出来交给上层(解析与编码、body 的解码与编码),axum 的 Bytes 提取器把整个 body 收成一个 Bytes(body 提取器)。freeze 之前的构建那一侧在 03 BytesMut。
💬 关联讨论
发起讨论加载中...