pub unsafe trait Allocator {
// Required methods
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
// Provided methods
fn allocate_zeroed(
&self,
layout: Layout
) -> Result<NonNull<[u8]>, AllocError> { ... }
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError> { ... }
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError> { ... }
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError> { ... }
fn by_ref(&self) -> &Self
where Self: Sized { ... }
}
allocator_api
#32838)Expand description
Allocator
的实现可以分配,增长,收缩和释放通过 Layout
描述的任意数据块。
Allocator
被设计为在 ZST、引用或智能指针上实现,因为像 MyAlloc([u8; N])
这样的分配器无法移动,而不更新指向已分配内存的指针。
与 GlobalAlloc
不同,Allocator
允许零大小的分配。
如果底层分配器不支持此功能 (例如 jemalloc) 或返回空指针 (例如 libc::malloc
),则必须由实现捕获。
当前分配的内存
某些方法要求通过分配器 currently 分配存储块。这意味着:
-
内存块随后并未被释放,其中的块要么通过传递到
deallocate
直接释放,要么通过传递到返回Ok
的grow
或shrink
进行了更改。
如果 grow
或 shrink
返回了 Err
,则传递的指针保持有效。
内存拟合
有些方法要求布局适合内存块。 对于到 “fit” 的布局,存储块意味着 (或者,对于到 “fit” 的存储块,布局意味着) 必须满足以下条件:
-
必须以与
layout.align()
相同的对齐方式分配该块,并且 -
提供的
layout.size()
必须在min ..= max
范围内,其中:
Safety
-
从分配器返回的内存块必须指向有效内存并保持其有效性,直到实例及其所有副本和克隆都丢弃,
-
复制、克隆或移动分配器不得使从该分配器返回的内存块无效。复制或克隆的分配器必须表现得像同一个分配器,并且
-
指向 currently allocated 的存储块的任何指针都可以传递给分配器的任何其他方法。
Required Methods§
sourcefn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
#32838)尝试分配一块内存。
成功后,返回满足 layout
大小和对齐保证的 NonNull<[u8]>
。
返回的块的大小可能大于 layout.size()
指定的大小,并且可能已初始化或未初始化其内容。
Errors
返回 Err
表示内存已耗尽,或者 layout
不满足分配器的大小或对齐约束。
鼓励实现在内存耗尽时返回 Err
,而不是 panic 或中止,但是这不是严格的要求。
(具体来说:在一个底层的原生分配库上实现此 trait 是 合法的,该本地分配库在内存耗尽时中止。)
鼓励希望响应分配错误而中止计算的客户端调用 handle_alloc_error
函数,而不是直接调用 panic!
或类似方法。
Provided Methods§
sourcefn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
#32838)行为类似于 allocate
,但也确保返回的内存被零初始化。
Errors
返回 Err
表示内存已耗尽,或者 layout
不满足分配器的大小或对齐约束。
鼓励实现在内存耗尽时返回 Err
,而不是 panic 或中止,但是这不是严格的要求。
(具体来说:在一个底层的原生分配库上实现此 trait 是 合法的,该本地分配库在内存耗尽时中止。)
鼓励希望响应分配错误而中止计算的客户端调用 handle_alloc_error
函数,而不是直接调用 panic!
或类似方法。
sourceunsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
#32838)尝试扩展内存块。
返回一个新的 NonNull<[u8]>
,其中包含一个指针和分配的内存的实际大小。该指针适用于保存 new_layout
描述的数据。
为此,分配器可以扩展 ptr
引用的分配以适合新的布局。
如果返回 Ok
,则 ptr
引用的内存块的所有权已转移到此分配器。
对旧 ptr
的任何访问都是未定义行为,即使分配是就地增长的。
新返回的指针是现在访问这块内存的唯一有效指针。
如果此方法返回 Err
,则该存储块的所有权尚未转移到此分配器,并且该存储块的内容未更改。
Safety
ptr
必须通过这个分配器来表示一块内存 currently allocated。old_layout
必须 fit 该内存块 (new_layout
参数不需要适合它。)。new_layout.size()
必须大于或等于old_layout.size()
。
请注意,new_layout.align()
不必与 old_layout.align()
相同。
Errors
如果新布局不符合分配器的大小和分配器的对齐约束,或者如果增长失败,则返回 Err
。
鼓励实现在内存耗尽时返回 Err
,而不是 panic 或中止,但是这不是严格的要求。
(具体来说:在一个底层的原生分配库上实现此 trait 是 合法的,该本地分配库在内存耗尽时中止。)
鼓励希望响应分配错误而中止计算的客户端调用 handle_alloc_error
函数,而不是直接调用 panic!
或类似方法。
sourceunsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
#32838)行为类似于 grow
,但也确保在返回新内容之前将其设置为零。
成功调用后,该存储块将包含以下内容
grow_zeroed
:
- 字节
0..old_layout.size()
从原始分配中保留。 - 字节
old_layout.size()..old_size
将保留还是清零,具体取决于分配器的实现。old_size
是指grow_zeroed
调用之前的内存块大小,可能比最初分配时请求的大小要大。 - 字节
old_size..new_size
被清零。new_size
是指grow_zeroed
调用返回的存储块的大小。
Safety
ptr
必须通过这个分配器来表示一块内存 currently allocated。old_layout
必须 fit 该内存块 (new_layout
参数不需要适合它。)。new_layout.size()
必须大于或等于old_layout.size()
。
请注意,new_layout.align()
不必与 old_layout.align()
相同。
Errors
如果新布局不符合分配器的大小和分配器的对齐约束,或者如果增长失败,则返回 Err
。
鼓励实现在内存耗尽时返回 Err
,而不是 panic 或中止,但是这不是严格的要求。
(具体来说:在一个底层的原生分配库上实现此 trait 是 合法的,该本地分配库在内存耗尽时中止。)
鼓励希望响应分配错误而中止计算的客户端调用 handle_alloc_error
函数,而不是直接调用 panic!
或类似方法。
sourceunsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn shrink( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
#32838)尝试缩小内存块。
返回一个新的 NonNull<[u8]>
,其中包含一个指针和分配的内存的实际大小。该指针适用于保存 new_layout
描述的数据。
为此,分配器可以缩小 ptr
引用的分配以适合新的布局。
如果返回 Ok
,则 ptr
引用的内存块的所有权已转移到此分配器。
对旧 ptr
的任何访问都是未定义行为,即使分配已就地收缩。
新返回的指针是现在访问这块内存的唯一有效指针。
如果此方法返回 Err
,则该存储块的所有权尚未转移到此分配器,并且该存储块的内容未更改。
Safety
ptr
必须通过这个分配器来表示一块内存 currently allocated。old_layout
必须 fit 该内存块 (new_layout
参数不需要适合它。)。new_layout.size()
必须小于或等于old_layout.size()
。
请注意,new_layout.align()
不必与 old_layout.align()
相同。
Errors
如果新的布局不符合分配器的大小和分配器的对齐约束,或者缩小失败,则返回 Err
。
鼓励实现在内存耗尽时返回 Err
,而不是 panic 或中止,但是这不是严格的要求。
(具体来说:在一个底层的原生分配库上实现此 trait 是 合法的,该本地分配库在内存耗尽时中止。)
鼓励希望响应分配错误而中止计算的客户端调用 handle_alloc_error
函数,而不是直接调用 panic!
或类似方法。