Skip to content

Commit 27cb21c

Browse files
authored
feat: 更新内存分配器的介绍
1 parent f660fa5 commit 27cb21c

File tree

3 files changed

+85
-27
lines changed

3 files changed

+85
-27
lines changed

course/advanced/memory_manage.md

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ outline: deep
1010

1111
事实上,zig 本身的标准库为我们提供了多种内存分配模型:
1212

13-
1. [`GeneralPurposeAllocator`](https://ziglang.org/documentation/master/std/#std.heap.general_purpose_allocator.GeneralPurposeAllocator)
14-
2. [`FixedBufferAllocator`](https://ziglang.org/documentation/master/std/#std.heap.FixedBufferAllocator)
15-
3. [`ArenaAllocator`](https://ziglang.org/documentation/master/std/#std.heap.arena_allocator.ArenaAllocator)
16-
4. [`HeapAllocator`](https://ziglang.org/documentation/master/std/#std.heap.HeapAllocator)
13+
1. [`DebugAllocator`](https://ziglang.org/documentation/master/std/#std.heap.debug_allocator.DebugAllocator)
14+
2. [`SmpAllocator`](https://ziglang.org/documentation/master/std/#std.heap.SmpAllocator)
15+
3. [`FixedBufferAllocator`](https://ziglang.org/documentation/master/std/#std.heap.FixedBufferAllocator)
16+
4. [`ArenaAllocator`](https://ziglang.org/documentation/master/std/#std.heap.arena_allocator.ArenaAllocator)
1717
5. [`c_allocator`](https://ziglang.org/documentation/master/std/#std.heap.c_allocator)
1818
6. [`page_allocator`](https://ziglang.org/documentation/master/std/#std.heap.page_allocator)
1919
7. [`StackFallbackAllocator`](https://ziglang.org/documentation/master/std/#std.heap.StackFallbackAllocator)
@@ -28,10 +28,7 @@ outline: deep
2828

2929
- `std.testing.FailingAllocator`
3030
- `std.testing.allocator`
31-
- `std.heap.LoggingAllocator`
32-
- `std.heap.LogToWriterAllocator`
3331
- `std.heap.SbrkAllocator`
34-
- `std.heap.ScopedLoggingAllocator`
3532

3633
:::
3734

@@ -41,13 +38,31 @@ outline: deep
4138

4239
:::
4340

44-
## `GeneralPurposeAllocator`
41+
## `DebugAllocator`
4542

46-
这是一个通用的分配器,当你需要动态内存时,并且还不知道自己应该用什么分配器模型,用这个准没错
43+
这是一个用于调试的分配器,现阶段适用于在调试模式下使用该分配器,它的性能并不高
4744

4845
这个分配器的目的不是为了性能,而是为了安全,它支持线程安全,安全检查,检查是否存在泄露等特性,这些特性均可手动配置是否开启。
4946

50-
<<<@/code/release/memory_manager.zig#GeneralPurposeAllocator
47+
<<<@/code/release/memory_manager.zig#DebugAllocator
48+
49+
## `SmpAllocator`
50+
51+
专为 `ReleaseFast` 优化设计的分配器,启用多线程。
52+
53+
这个分配器是一个单例;它使用全局状态,并且整个过程只应实例化一个。
54+
55+
设计思路:
56+
57+
1. 每个线程都有独立的空闲列表(freelist),但是当线程退出时,这些数据必须是可回收的。由于我们无法直接得知线程何时退出,所以偶尔需要一个线程尝试回收其他线程的资源。
58+
59+
2. 超过特定大小的内存分配会直接通过内存映射(memory mapped)实现,且不存储分配元数据。这种机制之所以可行,是因为实现中禁止了将分配从小类别转移到大类别(反之亦然)的大小调整。
60+
61+
3. 每个分配器操作都会通过线程局部变量检查线程标识符,以确定要访问全局状态中的哪个元数据,并尝试获取其锁。通常情况下,这个操作会在没有竞争的情况下成功,除非另一个线程被分配了相同的 ID。如果发生这种竞争情况,线程会移动到下一个线程元数据槽位并重复尝试获取锁的过程。
62+
63+
4. 通过将线程局部元数据数组限制为与 CPU 数量相同的大小,确保了随着线程的创建和销毁,它们会循环使用整个空闲列表集合。
64+
65+
<<<@/code/release/memory_manager.zig#SmpAllocator
5166

5267
## `FixedBufferAllocator`
5368

@@ -67,14 +82,6 @@ outline: deep
6782

6883
<<<@/code/release/memory_manager.zig#ArenaAllocator
6984

70-
## `HeapAllocator`
71-
72-
这是一个依赖 windows 特性的分配器模型,故仅可在 windows 下可用。
73-
74-
关于这个模型的更多信息,可以参考这里[https://learn.microsoft.com/en-us/windows/win32/api/heapapi/](https://learn.microsoft.com/en-us/windows/win32/api/heapapi/)
75-
76-
<<<@/code/release/memory_manager.zig#HeapAllocator
77-
7885
## `c_allocator`
7986

8087
这是纯粹的 C 的 `malloc`,它会直接尝试调用 C 库的内存分配,使用它需要在 `build.zig` 中添加上 `linkLibC` 功能:
@@ -85,7 +92,7 @@ outline: deep
8592

8693
它还有一个变体:[`raw_c_allocator`](https://ziglang.org/documentation/master/std/#std.heap.raw_c_allocator)
8794

88-
这两者的区别仅仅是 `c_allocator` 可能会调用 `alloc_aligned `而不是 `malloc` ,会优先使用 `malloc_usable_size` 来进行一些检查。
95+
这两者的区别仅仅是 `c_allocator` 可能会调用 `alloc_aligned`而不是 `malloc` ,会优先使用 `malloc_usable_size` 来进行一些检查。
8996

9097
`raw_c_allocator` 则是完全只使用 `malloc`
9198

@@ -128,4 +135,4 @@ outline: deep
128135

129136
待添加,当前你可以通过实现 `Allocator` 接口来实现自己的分配器。为了做到这一点,必须仔细阅读 [`std/mem.zig`](https://github.com/ziglang/zig/blob/master/lib/std/mem.zig) 中的文档注释,然后提供 `allocFn``resizeFn`
130137

131-
有许多分配器示例可供查看以获取灵感。查看 [`std/heap.zig`](https://github.com/ziglang/zig/blob/master/lib/std/heap.zig)[`std.heap.GeneralPurposeAllocator`](https://github.com/ziglang/zig/blob/master/lib/std/heap/general_purpose_allocator.zig)
138+
有许多分配器示例可供查看以获取灵感。查看 [`std/heap.zig`](https://github.com/ziglang/zig/blob/master/lib/std/heap.zig)[`std.heap.DebugAllocator`](https://github.com/ziglang/zig/blob/master/lib/std/heap/debug_allocator.zig)

course/basic/define-variable.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ pub usingnamespace @cImport({
157157
});
158158
```
159159

160+
相关的使用方法可以是这样的:
161+
162+
```zig
163+
pub usingnamespace @cImport({
164+
@cInclude("xcb/xcb.h");
165+
@cInclude("xcb/xproto.h");
166+
});
167+
```
168+
169+
针对以上的引入的头文件,我们可以这样使用 `@This().xcb_generic_event_t`
170+
160171
> [!IMPORTANT]
161172
> 初次阅读此处困惑是正常的,后面的概念学习完成后此处自通。
162173

course/code/14/memory_manager.zig

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
const builtin = @import("builtin");
21
pub fn main() !void {
3-
try GPA.main();
2+
try DebugAllocator.main();
3+
try SmpAllocator.main();
4+
try BestAllocator.main();
45
try FixedBufferAllocator.main();
56
try ThreadSafeFixedBufferAllocator.main();
67
try ArenaAllocator.main();
@@ -10,17 +11,17 @@ pub fn main() !void {
1011
try MemoryPool.main();
1112
}
1213

13-
const GPA = struct {
14-
// #region GeneralPurposeAllocator
14+
const DebugAllocator = struct {
15+
// #region DebugAllocator
1516
const std = @import("std");
1617

1718
pub fn main() !void {
1819
// 使用模型,一定要是变量,不能是常量
19-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
20+
var gpa = std.heap.DebugAllocator(std.heap.DebugAllocatorConfig{}){};
2021
// 拿到一个allocator
2122
const allocator = gpa.allocator();
2223

23-
// defer 用于执行general_purpose_allocator善后工作
24+
// defer 用于执行debug_allocator善后工作
2425
defer {
2526
// 尝试进行 deinit 操作
2627
const deinit_status = gpa.deinit();
@@ -34,7 +35,23 @@ const GPA = struct {
3435
// 延后释放内存
3536
defer allocator.free(bytes);
3637
}
37-
// #endregion GeneralPurposeAllocator
38+
// #endregion DebugAllocator
39+
};
40+
41+
const SmpAllocator = struct {
42+
// #region SmpAllocator
43+
const std = @import("std");
44+
45+
pub fn main() !void {
46+
// 无需任何初始化,拿来就可以使用
47+
const allocator = std.heap.smp_allocator;
48+
49+
//申请内存
50+
const bytes = try allocator.alloc(u8, 100);
51+
// 延后释放内存
52+
defer allocator.free(bytes);
53+
}
54+
// #endregion SmpAllocator
3855
};
3956

4057
const FixedBufferAllocator = struct {
@@ -83,6 +100,29 @@ const ThreadSafeFixedBufferAllocator = struct {
83100
// #endregion ThreadSafeFixedBufferAllocator
84101
};
85102

103+
const BestAllocator = struct {
104+
const std = @import("std");
105+
const builtin = @import("builtin");
106+
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
107+
108+
pub fn main() !void {
109+
const allocator, const is_debug = allocator: {
110+
if (builtin.os.tag == .wasi) break :allocator .{ std.heap.wasm_allocator, false };
111+
break :allocator switch (builtin.mode) {
112+
.Debug, .ReleaseSafe => .{ debug_allocator.allocator(), true },
113+
.ReleaseFast, .ReleaseSmall => .{ std.heap.smp_allocator, false },
114+
};
115+
};
116+
defer if (is_debug) {
117+
_ = debug_allocator.deinit();
118+
};
119+
//申请内存
120+
const bytes = try allocator.alloc(u8, 100);
121+
// 延后释放内存
122+
defer allocator.free(bytes);
123+
}
124+
};
125+
86126
const ArenaAllocator = struct {
87127
// #region ArenaAllocator
88128
const std = @import("std");

0 commit comments

Comments
 (0)