智能高效內存分配器測試報告

一、項目背景

  1. 這個項目是為了學習和實現一個高性能、特別是高并發場景下的內存分配器。這個項目是基于谷歌開源項目tcmalloc(Thread-Caching Malloc)實現的。tcmalloc 的核心目標就是替代系統默認的 malloc/free,在多線程環境下提供更高效的內存管理。
  2. C/C++的malloc雖然通用,但在高并發環境下,頻繁申請和釋放內存會引起劇烈鎖競爭,進而造成性能瓶頸。
  3. 理解tcmalloc這個項目,不僅是深入 C++ 高性能編程、提升技術深度的絕佳途徑,也是鞏固C++學習的重要方式。

二、項目功能

項目介紹

采取三層結構:thread_cache-central_cache-page_cache。當一個線程需要申請內存時,先向thread cache進行申請,thread cache沒有內存,轉而向central cache進行申請,central cache沒有內存,轉而向page cache進行申請,page cache沒有內存,會直接在堆上進行開辟。

? 在進行歸還內存時,不會直接釋放掉,直接釋放掉下次申請還要再進行上面的流程。對thread cache增加自由鏈表的結構,每次用完釋放后,直接將其鏈入thread cache的自由鏈表中,待自由鏈表長度過長或占用內存過大,我們在統一進行回收合并,這樣也能解決外碎片問題。

? 這三層結構主要解決小于和等于256KB大小的內存申請和釋放問題,對于申請和釋放大于256KB的內存塊,直接向page cache進行申請和釋放。

? **thread cache:**對于小塊內存進行管理,這個是每個線程獨有的,這里不存在線程安全問題,不用進行加鎖,每個線程獨享一個cache。

? **central cache:**中心緩存,所有線程共享的,thread cache按需從里面申請內存,會在合適時候對thread cache進行回收,以達到內存調度。central cache這里會存在內存競爭的問題,所以需要加鎖。

? **page cache:**是以頁為單位進行存儲和分配的,central cache向其申請對象時,page cache會給出若干頁,進行切割定長內存小塊分配給central cache。當若干頁進行回收后,會進行合并,解決了內存碎片問題(外碎片)

項目目標

  1. 高性能: 絕大多數小內存分配在 Thread Cache 無鎖完成,大幅提升并發性能。
  2. 低鎖競爭: 通過線程私有緩存和批量操作,將全局鎖競爭降到最低(主要在 Central Cache 的桶鎖)。
  3. 碎片控制: Page Cache 的合并機制有效緩解了外部碎片問題。

三、測試計劃

單元測試

**一般測試:**測試是否能正常工作
void Test_ConcurrentAlloc1()
{int* p1 = (int*)ConcurrentAlloc(6); //maxsize:2 allocnum:1 size:0int* p2 = (int*)ConcurrentAlloc(7); //3 2 1int* p3 = (int*)ConcurrentAlloc(8); //3   0int* p4 = (int*)ConcurrentAlloc(1); //4 3 2int* p5 = (int*)ConcurrentAlloc(1); //4   1int* p6 = (int*)ConcurrentAlloc(1); //4   0int* p7 = (int*)ConcurrentAlloc(1); //5 4 3*p1 = 10;*p2 = 20;*p3 = 30;*p4 = 40;cout << p1 << ": " << *p1 << endl;cout << p2 << ": " << *p2 << endl;cout << p3 << ": " << *p3 << endl;cout << p4 << ": " << *p4 << endl;ConcurrentFree(p1); //maxsize:5 size:4 span._usecount:10ConcurrentFree(p2); //5 0 5ConcurrentFree(p3); //5 1 5ConcurrentFree(p4); //5 2 5ConcurrentFree(p5); //5 3 5ConcurrentFree(p6); //5 4 5ConcurrentFree(p7); //5 0 0 
}

運行結果:

在這里插入圖片描述

特殊測試:是否可以分配大塊內存
void Test_BigAlloc()
{int *p1 = (int *)ConcurrentAlloc(MAX_BYTES + 100);int *p2 = (int *)ConcurrentAlloc(NPAGES << PAGE_SHIFT);*p1 = 10;*p2 = 20;cout << p1 << ": " << *p1 << endl;cout << p2 << ": " << *p2 << endl;ConcurrentFree(p1);ConcurrentFree(p2);
}

測試結果:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

基準測試

// ntimes 一輪申請和釋放內存的次數
// rounds 輪次
void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{std::vector<std::thread> vthread(nworks);std::atomic<size_t> malloc_costtime = 0;std::atomic<size_t> free_costtime = 0;for (size_t k = 0; k < nworks; ++k){vthread[k] = std::thread([&, k]() {std::vector<void*> v;v.reserve(ntimes);for (size_t j = 0; j < rounds; ++j){size_t begin1 = clock();for (size_t i = 0; i < ntimes; i++){//v.push_back(malloc(16));v.push_back(malloc((16 + i) % 8192 + 1));}size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < ntimes; i++){free(v[i]);}size_t end2 = clock();v.clear();malloc_costtime += (end1 - begin1);free_costtime += (end2 - begin2);}});}for (auto& t : vthread){t.join();}printf("%u個線程并發執行%u輪次,每輪次malloc %u次: 花費:%u ms\n",nworks, rounds, ntimes, (unsigned int)malloc_costtime);printf("%u個線程并發執行%u輪次,每輪次free %u次: 花費:%u ms\n",nworks, rounds, ntimes, (unsigned int)free_costtime);printf("%u個線程并發malloc&free %u次,總計花費:%u ms\n",nworks, nworks * rounds * ntimes, (unsigned int)malloc_costtime + free_costtime);
}// 單輪次申請釋放次數 線程數 輪次
void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{std::vector<std::thread> vthread(nworks);std::atomic<size_t> malloc_costtime = 0;std::atomic<size_t> free_costtime = 0;for (size_t k = 0; k < nworks; ++k){vthread[k] = std::thread([&]() {std::vector<void*> v;v.reserve(ntimes);for (size_t j = 0; j < rounds; ++j){size_t begin1 = clock();for (size_t i = 0; i < ntimes; i++){//v.push_back(ConcurrentAlloc(16));v.push_back(ConcurrentAlloc((16 + i) % 8192 + 1));}size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < ntimes; i++){ConcurrentFree(v[i]);}size_t end2 = clock();v.clear();malloc_costtime += (end1 - begin1);free_costtime += (end2 - begin2);}});}for (auto& t : vthread){t.join();}printf("%u個線程并發執行%u輪次,每輪次concurrent alloc %u次: 花費:%u ms\n",nworks, rounds, ntimes, (unsigned int)malloc_costtime);printf("%u個線程并發執行%u輪次,每輪次concurrent dealloc %u次: 花費:%u ms\n",nworks, rounds, ntimes, (unsigned int)free_costtime);printf("%u個線程并發concurrent alloc&dealloc %u次,總計花費:%u ms\n",nworks, nworks * rounds * ntimes, malloc_costtime + free_costtime);
}int main()
{size_t n = 10000;cout << "==========================================================" << endl;BenchmarkConcurrentMalloc(n, 10, 10);cout << endl << endl;BenchmarkMalloc(n, 10, 10);cout << "==========================================================" << endl;return 0;
}

測試結果:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

性能測試

多線程環境下的內存分配/釋放壓力測試:
void MultiThreadAlloc1()
{std::vector<void*> v;for (size_t i = 0; i < 7; ++i){void* ptr = ConcurrentAlloc(6);v.push_back(ptr);}for (auto e : v){ConcurrentFree(e);}
}

測試結果:

  1. ThreadCache 的批量分配和釋放機制
  2. 對象在ThreadCache和CentralCache間的流動
  3. 內存池的資源保留策略
  4. 整個生命周期沒有內存泄漏
內存碎片化測試:
void TestFragmentation() {const int BLOCK_COUNT = 500;std::vector<void*> mediumBlocks;std::vector<void*> smallBlocks;// 分配中型內存塊 (32KB)for (int i = 0; i < BLOCK_COUNT; ++i) {mediumBlocks.push_back(ConcurrentAlloc(32 * 1024));}// 釋放75%的中型塊(制造碎片)for (int i = 0; i < BLOCK_COUNT * 3/4; ++i) {ConcurrentFree(mediumBlocks[i]);}// 分配大量小內存塊 (128B)for (int i = 0; i < BLOCK_COUNT * 10; ++i) {smallBlocks.push_back(ConcurrentAlloc(128));}// 嘗試分配大內存塊void* bigBlock = ConcurrentAlloc(128 * 1024);assert(bigBlock != nullptr && "Fragmentation may be too high!");// 清理ConcurrentFree(bigBlock);for (auto p : smallBlocks) ConcurrentFree(p);for (int i = BLOCK_COUNT * 3/4; i < BLOCK_COUNT; ++i) {ConcurrentFree(mediumBlocks[i]);}std::cout << "Fragmentation Test: Passed\n";
}

測試結果:

  1. 在高度碎片化的環境中仍能分配大內存塊
  2. 自動合并相鄰空閑Span的能力
  3. 正確處理不同大小內存塊的混合分配
  4. 資源完全回收無泄漏

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95570.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95570.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95570.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

吱吱企業通訊軟件以安全為核心,構建高效溝通與協作一體化平臺

隨著即時通訊工具日益普及&#xff0c;企業面臨一個嚴峻的挑戰&#xff1a;如何在保障通訊數據安全的前提下&#xff0c;提升辦公效率&#xff1f;為解決此問題&#xff0c;吱吱企業通訊軟件誕生&#xff0c;通過私有化部署和深度集成的辦公系統&#xff0c;為企業打造一個既可…

校企合作| 長春大學旅游學院副董事長張海濤率隊到訪卓翼智能,共繪無人機技術賦能“AI+文旅”發展新藍圖

為積極響應國務院《關于深入實施“人工智能”行動的意見》&#xff08;國發〔2025〕11號&#xff09;號召&#xff0c;扎實推進學校“旅游”與“人工智能”雙輪驅動的學科發展戰略&#xff0c;加快無人機技術在文旅領域的創新應用&#xff0c;近日長春大學旅游學院副董事長張海…

為什么要用 MarkItDown?以及如何使用它

在處理大量文檔時&#xff0c;尤其是在構建知識庫、進行文檔分析或訓練大語言模型&#xff08;LLM&#xff09;時&#xff0c;將各種格式的文件&#xff08;如 PDF、Word、Excel、PPT、HTML 等&#xff09;轉換為統一的 Markdown 格式&#xff0c;能夠顯著提高處理效率和兼容性…

LVGL9.3 vscode 模擬環境搭建

1、git 克隆&#xff1a; git clone -b release/v9.3 https://github.com/lvgl/lv_port_pc_vscode.git 2、cmake 和 mingw 環境搭建 cmake&#xff1a; https://blog.csdn.net/qq_51355375/article/details/139186681?spm1011.2415.3001.5331 mingw&#xff1a; https://bl…

投影矩陣:計算機圖形學中的三維到二維轉換

投影矩陣是計算機圖形學中的核心概念之一&#xff0c;它負責將三維場景中的幾何數據投影到二維屏幕上&#xff0c;從而實現三維到二維的轉換。無論是游戲開發、虛擬現實&#xff0c;還是3D建模&#xff0c;投影矩陣都扮演著不可或缺的角色。本文將深入探討投影矩陣的基本原理、…

10.2 工程學中的矩陣(2)

十、例題 【例3】求由彈簧連接的 100100100 個質點的位移 u(1),u(2),...,u(100)u(1),u(2),...,u(100)u(1),u(2),...,u(100), 彈性系數均為 c1c 1c1, 每個質點受到的外力均為 f(i)0.01f(i)0.01f(i)0.01. 畫出兩端固定和固定-自由這兩種情形 u 的圖形。 解&#xff1a; % 參數設…

Mysql主從復制之延時同步

1.延時同步概念通過人為配置從庫和主庫延時N小時可以實現延時同步&#xff0c;延時同步可以解決數據庫故障出現的數據丟失問題(物理損壞如直接使用rm刪除數據庫數據和邏輯損壞如使用drop命令刪除數據庫)2.延時同步實操2.1先配置從庫延時同步&#xff0c;并且設置sql線程300秒后…

【QT特性技術講解】QPrinter、QPdf

前言 QT對打印和PDF應用場景&#xff0c;做了簡單的封裝&#xff0c;復雜的功能還是得用第三方庫&#xff0c;打印功能簡單的文本可以不用PDF&#xff0c;涉及圖形的基本都要用到PDF。 Linux打印 隨著國產信創項目替換基于Linux的桌面系統國產信創系統&#xff0c;Linux桌面系…

【大數據技術實戰】Flink+DS+Dinky 自動化構建數倉平臺

一、背景&#xff1a;企業數倉建設的現狀與挑戰在數字化轉型進入深水區的今天&#xff0c;數據已成為企業核心生產要素&#xff0c;而實時數倉作為 “數據驅動決策” 的關鍵載體&#xff0c;其建設水平直接決定企業在市場競爭中的響應速度與決策精度。根據 IDC《2024 年全球大數…

Python開篇:撬動未來的萬能鑰匙 —— 從入門到架構的全鏈路指南

Python&#xff1a;撬動未來的萬能鑰匙——從入門到架構的全鏈路指南 在技術的星空中&#xff0c;Python 是那顆永不隕落的超新星——它用簡潔的語法點燃創造之火&#xff0c;以龐大的生態鋪就革新之路。無論你身處哪個領域&#xff0c;這把鑰匙正在打開下一個時代的大門。2024…

【QT隨筆】事件過濾器(installEventFilter 和 eventFilter 的組合)之生命周期管理詳解

【QT隨筆】事件過濾器(installEventFilter 和 eventFilter 的組合)之生命周期管理詳解 上一章節中提到事件過濾器(Event Filter),用于處理特定事件。其中第二小節中提到了事件過濾器生命周期管理。本文將詳細解析事件過濾器生命周期管理這一部分的內容。 (關注不迷路哈!…

關于linux軟件編程12——網絡編程3

一、單循環服務器 特點:1.可以處理多個客戶端 (不能同時)2.效率不高//單循環服務器: socket bind listen while (1) {connfd accept();//通信 }特點:簡單 可以處理多客戶端 不能同時 二、并發服務器 --- 同時可以處理多個客戶端1、設置一個選項(開啟一個功能) ---讓地址重…

thinkphp6通過workerman使用websocket

安裝workerman依賴 composer require topthink/think-worker composer require topthink/think-worker1.0.* # 指定兼容版本?:ml-citation{ref"1,7" data"citationList"}config配置 config/worker.php <?php return [// 擴展自身需要的配置host …

Rust SQLx 開發指南:利用 Tokio 進行性能優化

在當今高并發的應用開發環境中&#xff0c;數據庫操作往往是性能瓶頸的主要來源之一。SQLx 作為一個純 Rust 編寫的異步 SQL 客戶端庫&#xff0c;通過與 Tokio 運行時深度集成&#xff0c;為開發者提供了處理數據庫 I/O 密集型操作的強大工具。本文將帶您深入了解如何利用這兩…

嵌入式硬件電路分析---AD采集電路

文章目錄摘要AD采集電路1AD采集電路2R77的真正作用是什么&#xff1f;理想與現實&#xff1a;為什么通常可以忽略R77的影響&#xff1f;摘要 AD采集 AD采集電路1 這是個人畫的簡化后的AD采集電路 這是一個AD檢測電路&#xff0c;R1是一個可變電阻&#xff0c;R2是根據R1的常用…

Python爬取nc數據

1、單文件爬取爬取該網站下的crupre.nc數據&#xff0c;如下使用requests庫&#xff0c;然后填寫網站的url&#xff1a;"http://clima-dods.ictp.it/regcm4/CLM45/crudata/"和需要下載的文件名&#xff1a;"crupre.nc"import requests import osdef downlo…

策略模式 + 工廠模式

策略模式&#xff1a;簡單來說解決的行為的封裝與選擇。如HandlerMapping&#xff0c;將 HTTP 請求映射到對應的處理器&#xff08;Controller 或方法&#xff09;。工廠模式&#xff1a;解決的是具有相同屬性的對象創建問題&#xff0c;如BeanFactory創建bean對象。解決的代碼…

Diamond基礎3:在線邏輯分析儀Reveal的使用

文章目錄1. 與ILA的區別2. 使用Reveal步驟3.Reveal注意事項4.傳送門1. 與ILA的區別 Reveal是Lattice Diamond集成開發環境用于在線監測信號的工具&#xff0c;ILA是xilinx的Vivado集成開發工具的在線邏輯分析儀&#xff0c;同Reveal一樣&#xff0c;均可以在項目運行過程中&am…

超適合程序員做知識整理的 AI 網站

這次要給大家分享一個超適合程序員做知識整理的 AI 網站 ——Notion AI&#xff0c;網址是Notion&#xff0c;它能把你隨手記的雜亂筆記、代碼片段、技術文檔&#xff0c;一鍵梳理成邏輯清晰的結構化內容&#xff0c;小索奇我用它整理 “Python 爬蟲知識點” 時&#xff0c;原本…

【 Selenium 爬蟲】2025年8月25日-pixabay 圖片采集

無惡意采集&#xff0c;取部分圖片用來做相冊測試的&#x1f604; 效果圖import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.la.selenium.utils.SeleniumUtil; import lombok.extern.slf4j.Slf4j; import o…