|
22 | 22 | - [page\_cache内存释放](#page_cache内存释放) |
23 | 23 | - [大于256k的情况](#大于256k的情况) |
24 | 24 | - [处理代码中`new`的问题](#处理代码中new的问题) |
| 25 | + - [解决free,使其不用传大小](#解决free使其不用传大小) |
| 26 | + - [多线程场景下深度测试](#多线程场景下深度测试) |
| 27 | + - [分析性能瓶颈](#分析性能瓶颈) |
| 28 | + - [用Radix Tree进行优化](#用radix-tree进行优化) |
25 | 29 |
|
26 | 30 | *** |
27 | 31 |
|
@@ -1196,4 +1200,92 @@ void page_cache::release_span_to_page(span* s) { |
1196 | 1200 |
|
1197 | 1201 | ## 处理代码中`new`的问题 |
1198 | 1202 |
|
1199 | | -代码中有些地方用了`new span`。这个就很不对。我们弄这个tcmalloc是用来替代malloc的,既然是替代,那我们的代码里面怎么能有`new`,`new`也是调用`malloc`的,所以我们要改一下。 |
| 1203 | +代码中有些地方用了`new span`。这个就很不对。我们弄这个tcmalloc是用来替代malloc的,既然是替代,那我们的代码里面怎么能有`new`,`new`也是调用`malloc`的,所以我们要改一下。 |
| 1204 | + |
| 1205 | +然后之前是写了一个定长内存池的,可以用来代替new。 |
| 1206 | + |
| 1207 | +**博客地址:[内存池是什么原理?|内存池简易模拟实现|为学习高并发内存池tcmalloc做准备](https://blog.csdn.net/Yu_Cblog/article/details/131741601)** |
| 1208 | + |
| 1209 | +page_cache.hpp |
| 1210 | +```cpp |
| 1211 | +class page_cache { |
| 1212 | +private: |
| 1213 | + span_list __span_lists[PAGES_NUM]; |
| 1214 | + static page_cache __s_inst; |
| 1215 | + page_cache() = default; |
| 1216 | + page_cache(const page_cache&) = delete; |
| 1217 | + std::unordered_map<PAGE_ID, span*> __id_span_map; |
| 1218 | + object_pool<span> __span_pool; |
| 1219 | +``` |
| 1220 | +多加一个`object_pool<span> __span_pool;`对象。 |
| 1221 | +
|
| 1222 | +然后,`new span`的地方都替换掉。`delete`的地方也换掉就行。 |
| 1223 | +
|
| 1224 | +然后这里面也改一下。 |
| 1225 | +
|
| 1226 | +tcmalloc.hpp |
| 1227 | +```cpp |
| 1228 | +static void* tcmalloc(size_t size) { |
| 1229 | + if (size > MAX_BYTES) { |
| 1230 | + // 处理申请大内存的情况 |
| 1231 | + size_t align_size = size_class::round_up(size); |
| 1232 | + size_t k_page = align_size >> PAGE_SHIFT; |
| 1233 | + page_cache::get_instance()->__page_mtx.lock(); |
| 1234 | + span* cur_span = page_cache::get_instance()->new_span(k_page); // 直接找pc |
| 1235 | + page_cache::get_instance()->__page_mtx.unlock(); |
| 1236 | + void* ptr = (void*)(cur_span->__page_id << PAGE_SHIFT); // span转化成地址 |
| 1237 | + return ptr; |
| 1238 | + } |
| 1239 | + if (p_tls_thread_cache == nullptr) { |
| 1240 | + // 相当于单例 |
| 1241 | + // p_tls_thread_cache = new thread_cache; |
| 1242 | + static object_pool<thread_cache> tc_pool; |
| 1243 | + p_tls_thread_cache = tc_pool.new_(); |
| 1244 | + } |
| 1245 | +#ifdef PROJECT_DEBUG |
| 1246 | + LOG(DEBUG) << "tcmalloc find tc from mem" << std::endl; |
| 1247 | +#endif |
| 1248 | + return p_tls_thread_cache->allocate(size); |
| 1249 | +} |
| 1250 | +``` |
| 1251 | + |
| 1252 | +## 解决free,使其不用传大小 |
| 1253 | + |
| 1254 | +因为我们已经有页号到span的映射了。所以我们在span里面增加一个字段,obj_size就行。 |
| 1255 | + |
| 1256 | +## 多线程场景下深度测试 |
| 1257 | + |
| 1258 | +**首先要明确一点,我们不是去造一个轮子,我们要和malloc对比,不是说要比malloc快多少,因为我们在很多细节上,和tcmalloc差的还是很远的。** |
| 1259 | + |
| 1260 | +测试代码可以见bench\_mark.cc。 |
| 1261 | + |
| 1262 | +结果 |
| 1263 | +```bash |
| 1264 | +parallels@ubuntu-linux-22-04-desktop:~/Project/Google-tcmalloc-simulation-implementation$ ./out |
| 1265 | +========================================================== |
| 1266 | +4个线程并发执行10轮次,每轮次concurrent alloc 1000次: 花费:27877 ms |
| 1267 | +4个线程并发执行10轮次,每轮次concurrent dealloc 1000次: 花费:52190 ms |
| 1268 | +4个线程并发concurrent alloc&dealloc 40000次,总计花费:80067 ms |
| 1269 | + |
| 1270 | + |
| 1271 | +4个线程并发执行10次,每轮次malloc 1000次: 花费:2227ms |
| 1272 | +4个线程并发执行10轮次,每轮次free 1000次: 花费:1385 ms |
| 1273 | +4个线程并发malloc&free 40000次,总计花费:3612 ms |
| 1274 | +========================================================== |
| 1275 | +parallels@ubuntu-linux-22-04-desktop:~/Project/Google-tcmalloc-simulation-implementation$ |
| 1276 | +``` |
| 1277 | + |
| 1278 | +比malloc差。 |
| 1279 | + |
| 1280 | +## 分析性能瓶颈 |
| 1281 | + |
| 1282 | +linux和windows(VS STUDIO)下都有很多性能分析的工具,可以检测哪里调用的时间多。 |
| 1283 | + |
| 1284 | +在这里直接出结论:锁用了很多时间。 |
| 1285 | + |
| 1286 | +可以用基数树进行优化。 |
| 1287 | + |
| 1288 | +## 用Radix Tree进行优化 |
| 1289 | + |
| 1290 | +radix tree 我们可以直接用tcmalloc源码里面的。`page_map.hpp`。 |
| 1291 | + |
0 commit comments