-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory.hpp
More file actions
160 lines (142 loc) · 6.67 KB
/
memory.hpp
File metadata and controls
160 lines (142 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once
#include <iostream>
#include <vector>
#include <mutex>
#include <atomic>
#include <cassert>
#include <memory>
#include <cstddef>
#include <thread>
#include <algorithm>
// 内存对齐函数,把size向上对齐到align的整数倍,align是2的幂次方
static inline std::size_t align_up(std::size_t size, std::size_t align) {
return (size + align - 1) & ~(align - 1);
}
class FixedSizeMemory {
public:
// 定义链表头节点
struct Node { Node* next; };
// [新增]:手动刷新当前线程的缓存,将其归还给 Page
// 供线程退出清理或用户手动调用
void flush_thread_cache();
// 内存池的构造和析构函数
explicit FixedSizeMemory(std::size_t blocks_size, std::size_t blocks_per_page = 1024);
~FixedSizeMemory();
// 从内存池去除内存块(从链表去除一个节点)
void* allocate();
// 将内存块放回内存池(归还节点)
void deallocate(void* p) noexcept;
// 获取内存块大小
std::size_t get_blocks_size() const;
// 获取一页内存的内存块个数
std::size_t get_blocks_per_page() const;
// 诊断接口
std::size_t page_count() const noexcept;
std::size_t block_size() const noexcept;
std::size_t free_count() const noexcept;
std::size_t allocated_count() const;
private:
// 页结构体,实现一页一锁
struct alignas(64) Page {
// 页锁
std::mutex mtx;
// 链表头
Node* free_list = nullptr;
// 页起始地址
char* base = nullptr;
// 页容量
std::size_t capacity = 0;
// 已经使用的内存块数
std::size_t inuse = 0;
// 是否空闲(inuse是否为0)
bool is_empty_candidate = false;
// 析构
~Page();
};
// 辅助函数
void decommission_pages();
Page* expand();
// 内联辅助函数(必须在头文件中)
std::size_t adjusted_block_size(std::size_t size) const noexcept {
constexpr std::size_t node_size = sizeof(Node);
constexpr std::size_t node_align = alignof(Node);
size = std::max(size, node_size);
return align_up(size, node_align);
}
// 成员变量
// 全局锁
mutable std::mutex big_mtx_;
// 页集合的数组
std::vector<std::shared_ptr<Page>> pages_;
// 活跃操作计数器
std::atomic<std::size_t> active_ops_{0};
// 内存池是否关闭的标志
std::atomic<bool> shutdown_{false};
// 块大小(输入的大小)
std::size_t blocks_size;
// 一页的块的数量
std::size_t blocks_per_page;
// 原子计数器,已经分配的块数量
std::atomic<std::size_t> allocated{0};
// 内存对齐后的块大小(实际块的大小,构造时内存会对齐)
std::size_t adjusted_block_sz_ = 0;
// 惰性页(inuse == 0)
std::vector<Page*> empty_pages_;
// 惰性页回收的阔值
static constexpr double DECOMMISSION_THRESHOLD = 0.2;
// 线程本地缓存相关常量
static constexpr std::size_t LOCAL_CACHE_SIZE = 32; // 推荐值,可以根据测试调整
// 线程本地缓存为空时,一次从页批量获取的块数
static constexpr std::size_t REFILL_COUNT = LOCAL_CACHE_SIZE / 2;
// 从一个Page中批量获取 N 个块给线程本地缓存
void refill_local_list(std::size_t count);
// 将线程本地缓存中 N 个块批量归还给 Page
void drain_local_list(Node* head, std::size_t count);
};
// v1.0.0静态架构
// +----------------------------------------------------------+
// | FixedSizeMemory |
// |----------------------------------------------------------|
// | - free_list_head : Node* |
// | - blocks_size : size_t |
// | - blocks_per_page: size_t |
// | - pages : vector<void*> |
// |----------------------------------------------------------|
// | + allocate() : void* |
// | + deallocate(void*) : void |
// | + get_blocks_size() : size_t |
// | + get_blocks_per_page(): size_t |
// | + page_count() : size_t |
// | + block_size() : size_t (对齐后的大小) |
// | + free_count() : size_t (遍历空闲链表计数) |
// |----------------------------------------------------------|
// | private: |
// | ~ adjusted_block_size(size): size_t (≥sizeof(Node) 且对齐) |
// | ~ expand() : void (申请一页并切成块挂链) |
// +----------------------------------------------------------+
// v2.0.1静态架构
// +--------------------------------------------------------------------+
// | FixedSizeMemory |
// |--------------------------------------------------------------------|
// | - pages_ : vector<shared_ptr> |
// | - big_mtx_ : mutex |
// | - active_ops_ : atomic<size_t> |
// | - shutdown_ : atomic |
// | - blocks_size : size_t |
// | - blocks_per_page : size_t |
// | - allocated : atomic<size_t> |
// | - adjusted_block_sz_ : size_t |
// |--------------------------------------------------------------------|
// | + allocate() : void* |
// | + deallocate(void*) : void |
// | + get_blocks_size() : size_t |
// | + get_blocks_per_page(): size_t |
// | + page_count() : size_t |
// | + block_size() : size_t (对齐后的大小) |
// | + free_count() : size_t (遍历空闲链表计数) |
// |--------------------------------------------------------------------|
// | private: |
// | ~ adjusted_block_size(size): size_t (≥sizeof(Node) 且对齐) |
// | ~ expand() : Page* (申请一页并切成块挂链,返回新页)|
// | struct Page : 封装了每页的管理信息,包括mtx, free_list, base, capacity, inuse |
// +--------------------------------------------------------------------|