|
1 | | -# Google-tcmalloc-simulation-implementation |
| 1 | +# Google-tcmalloc-simulation-implementation(未完成) |
2 | 2 | 谷歌开源项目tcmalloc高并发内存池学习和模拟实现 |
3 | 3 |
|
4 | 4 | 开题日期:20240504 |
5 | 5 |
|
6 | | -- [Google-tcmalloc-simulation-implementation](#google-tcmalloc-simulation-implementation) |
| 6 | +- [Google-tcmalloc-simulation-implementation(未完成)](#google-tcmalloc-simulation-implementation未完成) |
| 7 | + - [==bugs to fix (项目目前待解决的问题)==](#bugs-to-fix-项目目前待解决的问题) |
7 | 8 | - [前言](#前言) |
8 | 9 | - [threadCache整体框架](#threadcache整体框架) |
9 | 10 | - [开始写threadCache代码](#开始写threadcache代码) |
|
22 | 23 | - [page\_cache内存释放](#page_cache内存释放) |
23 | 24 | - [大于256k的情况](#大于256k的情况) |
24 | 25 | - [处理代码中`new`的问题](#处理代码中new的问题) |
| 26 | + - [解决free,使其不用传大小](#解决free使其不用传大小) |
| 27 | + - [多线程场景下深度测试](#多线程场景下深度测试) |
| 28 | + - [分析性能瓶颈](#分析性能瓶颈) |
| 29 | + - [用Radix Tree进行优化](#用radix-tree进行优化) |
25 | 30 |
|
26 | 31 | *** |
27 | 32 |
|
| 33 | +## ==bugs to fix (项目目前待解决的问题)== |
| 34 | + |
| 35 | +1. 在ubuntu_arm64环境下,如果调用多线程,出现段错误(原因未知,待解决) |
| 36 | +2. 在ubuntu_arm64环境下,radix tree需要用第三棵,前两棵用不了,需要解决。 |
| 37 | +3. 在window32位环境下,可以偶尔成功运行,出现偶发段错误,原因未知,待解决。 |
| 38 | + |
| 39 | +经过radixtree优化后,模拟实现的tcmalloc效率高于malloc。(win32下测试,会出现偶发段错误) |
| 40 | + |
| 41 | + |
| 42 | + |
28 | 43 | ## 前言 |
29 | 44 |
|
30 | 45 | 当前项目是实现一个高并发的内存池,他的原型是google的一个开源项目tcmalloc,tcmalloc全称 Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替代系统的内存分配相关的函数(malloc、free)。 |
@@ -1196,4 +1211,92 @@ void page_cache::release_span_to_page(span* s) { |
1196 | 1211 |
|
1197 | 1212 | ## 处理代码中`new`的问题 |
1198 | 1213 |
|
1199 | | -代码中有些地方用了`new span`。这个就很不对。我们弄这个tcmalloc是用来替代malloc的,既然是替代,那我们的代码里面怎么能有`new`,`new`也是调用`malloc`的,所以我们要改一下。 |
| 1214 | +代码中有些地方用了`new span`。这个就很不对。我们弄这个tcmalloc是用来替代malloc的,既然是替代,那我们的代码里面怎么能有`new`,`new`也是调用`malloc`的,所以我们要改一下。 |
| 1215 | + |
| 1216 | +然后之前是写了一个定长内存池的,可以用来代替new。 |
| 1217 | + |
| 1218 | +**博客地址:[内存池是什么原理?|内存池简易模拟实现|为学习高并发内存池tcmalloc做准备](https://blog.csdn.net/Yu_Cblog/article/details/131741601)** |
| 1219 | + |
| 1220 | +page_cache.hpp |
| 1221 | +```cpp |
| 1222 | +class page_cache { |
| 1223 | +private: |
| 1224 | + span_list __span_lists[PAGES_NUM]; |
| 1225 | + static page_cache __s_inst; |
| 1226 | + page_cache() = default; |
| 1227 | + page_cache(const page_cache&) = delete; |
| 1228 | + std::unordered_map<PAGE_ID, span*> __id_span_map; |
| 1229 | + object_pool<span> __span_pool; |
| 1230 | +``` |
| 1231 | +多加一个`object_pool<span> __span_pool;`对象。 |
| 1232 | +
|
| 1233 | +然后,`new span`的地方都替换掉。`delete`的地方也换掉就行。 |
| 1234 | +
|
| 1235 | +然后这里面也改一下。 |
| 1236 | +
|
| 1237 | +tcmalloc.hpp |
| 1238 | +```cpp |
| 1239 | +static void* tcmalloc(size_t size) { |
| 1240 | + if (size > MAX_BYTES) { |
| 1241 | + // 处理申请大内存的情况 |
| 1242 | + size_t align_size = size_class::round_up(size); |
| 1243 | + size_t k_page = align_size >> PAGE_SHIFT; |
| 1244 | + page_cache::get_instance()->__page_mtx.lock(); |
| 1245 | + span* cur_span = page_cache::get_instance()->new_span(k_page); // 直接找pc |
| 1246 | + page_cache::get_instance()->__page_mtx.unlock(); |
| 1247 | + void* ptr = (void*)(cur_span->__page_id << PAGE_SHIFT); // span转化成地址 |
| 1248 | + return ptr; |
| 1249 | + } |
| 1250 | + if (p_tls_thread_cache == nullptr) { |
| 1251 | + // 相当于单例 |
| 1252 | + // p_tls_thread_cache = new thread_cache; |
| 1253 | + static object_pool<thread_cache> tc_pool; |
| 1254 | + p_tls_thread_cache = tc_pool.new_(); |
| 1255 | + } |
| 1256 | +#ifdef PROJECT_DEBUG |
| 1257 | + LOG(DEBUG) << "tcmalloc find tc from mem" << std::endl; |
| 1258 | +#endif |
| 1259 | + return p_tls_thread_cache->allocate(size); |
| 1260 | +} |
| 1261 | +``` |
| 1262 | + |
| 1263 | +## 解决free,使其不用传大小 |
| 1264 | + |
| 1265 | +因为我们已经有页号到span的映射了。所以我们在span里面增加一个字段,obj_size就行。 |
| 1266 | + |
| 1267 | +## 多线程场景下深度测试 |
| 1268 | + |
| 1269 | +**首先要明确一点,我们不是去造一个轮子,我们要和malloc对比,不是说要比malloc快多少,因为我们在很多细节上,和tcmalloc差的还是很远的。** |
| 1270 | + |
| 1271 | +测试代码可以见bench\_mark.cc。 |
| 1272 | + |
| 1273 | +结果 |
| 1274 | +```bash |
| 1275 | +parallels@ubuntu-linux-22-04-desktop:~/Project/Google-tcmalloc-simulation-implementation$ ./out |
| 1276 | +========================================================== |
| 1277 | +4个线程并发执行10轮次,每轮次concurrent alloc 1000次: 花费:27877 ms |
| 1278 | +4个线程并发执行10轮次,每轮次concurrent dealloc 1000次: 花费:52190 ms |
| 1279 | +4个线程并发concurrent alloc&dealloc 40000次,总计花费:80067 ms |
| 1280 | + |
| 1281 | + |
| 1282 | +4个线程并发执行10次,每轮次malloc 1000次: 花费:2227ms |
| 1283 | +4个线程并发执行10轮次,每轮次free 1000次: 花费:1385 ms |
| 1284 | +4个线程并发malloc&free 40000次,总计花费:3612 ms |
| 1285 | +========================================================== |
| 1286 | +parallels@ubuntu-linux-22-04-desktop:~/Project/Google-tcmalloc-simulation-implementation$ |
| 1287 | +``` |
| 1288 | + |
| 1289 | +比malloc差。 |
| 1290 | + |
| 1291 | +## 分析性能瓶颈 |
| 1292 | + |
| 1293 | +linux和windows(VS STUDIO)下都有很多性能分析的工具,可以检测哪里调用的时间多。 |
| 1294 | + |
| 1295 | +在这里直接出结论:锁用了很多时间。 |
| 1296 | + |
| 1297 | +可以用基数树进行优化。 |
| 1298 | + |
| 1299 | +## 用Radix Tree进行优化 |
| 1300 | + |
| 1301 | +radix tree 我们可以直接用tcmalloc源码里面的。`page_map.hpp`。 |
| 1302 | + |
0 commit comments