操作系統實現:malloc 與 堆 實現

来源:https://www.cnblogs.com/thotf/archive/2022/06/10/16360018.html
-Advertisement-
Play Games

本文參考書:操作系統真像還原 什麼是malloc? malloc 是用戶態申請記憶體時使用的函數。 malloc在哪裡申請? 堆中。 什麼是堆? 程式運行過程中需要申請額外的記憶體都會在堆中分配,堆中的記憶體分為幾個規格類型的塊用鏈表保存,程式需要記憶體就分配一個大於等於所需記憶體大小的塊。如果一個規格的塊用 ...


本文參考書:操作系統真像還原

 

什麼是malloc?

malloc 是用戶態申請記憶體時使用的函數。

 

malloc在哪裡申請?

堆中。

 

什麼是堆?

程式運行過程中需要申請額外的記憶體都會在堆中分配,堆中的記憶體分為幾個規格類型的塊用鏈表保存,程式需要記憶體就分配一個大於等於所需記憶體大小的塊。如果一個規格的塊用完了就像系統申請頁,再將頁切分成規格塊的大小一個一個用鏈錶鏈接起來。

 

如何找到堆?

一般堆在進程pcb處有指針,內核的堆可以是一個全局變數。

 

由以上幾個問題我們可以知道,只要先搞定堆後,malloc的作用就是在堆中拿個記憶體塊就好啦。

 

堆的結構圖

 

 

 堆的核心結構是個數組u_block_desc  代表用戶堆,放在進程pcb中。數組的每個元素mem_block_desc 代表不同類型的記憶體塊大小,每個記憶體塊用鏈錶鏈接。

 

幾個重要數據結構,下麵會進行解釋

/* 記憶體塊 */
struct mem_block {
   struct list_elem free_elem;
};

/* 記憶體塊描述符 */
struct mem_block_desc {
   uint32_t block_size;         // 記憶體塊大小
   uint32_t blocks_per_arena;     // 本arena中可容納此mem_block的數量.
   struct list free_list;     // 目前可用的mem_block鏈表
};
/* 記憶體倉庫arena元信息 */
struct arena {
struct mem_block_desc* desc; // 此arena關聯的mem_block_desc
/* large為ture時,cnt表示的是頁框數。
* 否則cnt表示空閑mem_block數量 */
uint32_t cnt;
bool large;
};

mem_block_desc 就是記憶體塊的信息,記錄著記憶體塊大小和鏈表

arena就是分配的頁,arena中記憶體塊切割大小由desc指定,如果所需記憶體塊過大,就不進行切割直接分配頁框,也就是large的作用。

記憶體分配過程如下

① 向堆申請可用記憶體時,沒有在所要用到的mem_block_desc下麵找到可用記憶體塊。向操作系統申請4K的頁,每個頁就是一個arena。

②對arena進行切分,分為所需mem_block_desc的大小,並且一個一個加入到mem_block_desc的鏈表中

③從鏈表上拿到一個記憶體塊並返回記憶體地址

 

 1 void* sys_malloc(uint32_t size) {
 2    enum pool_flags PF;
 3    struct pool* mem_pool;
 4    uint32_t pool_size;
 5    struct mem_block_desc* descs;
 6    struct task_struct* cur_thread = running_thread();
 7 
 8 /* 判斷用哪個記憶體池,內核也要從內核記憶體池申請頁*/
 9    if (cur_thread->pgdir == NULL) {     // 若為內核線程
10       PF = PF_KERNEL; 
11       pool_size = kernel_pool.pool_size;
12       mem_pool = &kernel_pool;
13       descs = k_block_descs;
14    } else {                      // 用戶進程pcb中的pgdir會在為其分配頁表時創建
15       PF = PF_USER;
16       pool_size = user_pool.pool_size;
17       mem_pool = &user_pool;
18       descs = cur_thread->u_block_desc;
19    }
20 
21    /* 若申請的記憶體不在記憶體池容量範圍內則直接返回NULL */
22    if (!(size > 0 && size < pool_size)) {
23       return NULL;
24    }
25    struct arena* a;
26    struct mem_block* b;    
27    lock_acquire(&mem_pool->lock);
28 
29 /* 超過最大記憶體塊1024, 就分配頁框 */
30    if (size > 1024) {
31       uint32_t page_cnt = DIV_ROUND_UP(size + sizeof(struct arena), PG_SIZE);    // 向上取整需要的頁框數
32 
33       a = malloc_page(PF, page_cnt);
34 
35       if (a != NULL) {
36      memset(a, 0, page_cnt * PG_SIZE);     // 將分配的記憶體清0  
37 
38       /* 對於分配的大塊頁框,將desc置為NULL, cnt置為頁框數,large置為true */
39      a->desc = NULL;
40      a->cnt = page_cnt;
41      a->large = true;
42      lock_release(&mem_pool->lock);
43      return (void*)(a + 1);         // 跨過arena大小,把剩下的記憶體返回
44       } else { 
45      lock_release(&mem_pool->lock);
46      return NULL; 
47       }
48    } else {    // 若申請的記憶體小於等於1024,可在各種規格的mem_block_desc中去適配
49       uint8_t desc_idx;
50       
51       /* 從記憶體塊描述符中匹配合適的記憶體塊規格 */
52       for (desc_idx = 0; desc_idx < DESC_CNT; desc_idx++) {
53      if (size <= descs[desc_idx].block_size) {  // 從小往大後,找到後退出
54         break;
55      }
56       }
57 
58    /* 若mem_block_desc的free_list中已經沒有可用的mem_block,
59     * 就創建新的arena提供mem_block */
60       if (list_empty(&descs[desc_idx].free_list)) {
61      a = malloc_page(PF, 1);       // 分配1頁框做為arena
62      if (a == NULL) {
63         lock_release(&mem_pool->lock);
64         return NULL;
65      }
66      memset(a, 0, PG_SIZE);  //清空頁數據
67 
68     /* 對於分配的小塊記憶體,將desc置為相應記憶體塊描述符, 
69      * cnt置為此arena可用的記憶體塊數,large置為false */
70      a->desc = &descs[desc_idx];
71      a->large = false;
72      a->cnt = descs[desc_idx].blocks_per_arena;
73      uint32_t block_idx;
74 
75      enum intr_status old_status = intr_disable();
76 
77      /* 開始將arena拆分成記憶體塊,並添加到記憶體塊描述符的free_list中 */
78      for (block_idx = 0; block_idx < descs[desc_idx].blocks_per_arena; block_idx++) {
79         b = arena2block(a, block_idx);
80         ASSERT(!elem_find(&a->desc->free_list, &b->free_elem));
81         list_append(&a->desc->free_list, &b->free_elem);    
82      }
83      intr_set_status(old_status);
84       }    
85 
86    /* 開始分配記憶體塊 */
87       b = elem2entry(struct mem_block, free_elem, list_pop(&(descs[desc_idx].free_list)));
88       memset(b, 0, descs[desc_idx].block_size);
89 
90       a = block2arena(b);  // 獲取記憶體塊b所在的arena
91       a->cnt--;           // 將此arena中的空閑記憶體塊數減1
92       lock_release(&mem_pool->lock);
93       return (void*)b;
94    }
95 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 來源:cnblogs.com/lwtyyds/p/15678152.html 常用類概述 內部類 Object類 包裝類 數學類 時間類 字元串 String Builder和StringBuffer DecimalFormat 內部類 「概念」 :在一個類內部再定義一個完整的類。 一般情況下類與類 ...
  • 0. 文章目的 面向有一定基礎的C#初學者,介紹C#中介面的意義、使用以及特點。 1. 閱讀基礎 瞭解C#基本語法(如定義一個類、繼承一個類) 理解OOP中的基本概念(如繼承,多態) 2. 什麼是介面 2.1 現實中的協定與介面 貓貓頭在整理電腦文件,需要一個小工具來分類文件,於是貓貓頭向群里求助: ...
  • 好久沒到園子裡面逛了,回來看了看,.NET有點式微呀?Java/Spring/Linux……比以前多了很多,為什麼?博客園可是.NET的大本營了呀! 好吧,我承認,飛哥也動搖了,去年在ASP.NET的基礎上,開了一期Java Web班。給大家彙報一下心得體會吧: 錄課程前 其實我最開始學(2008年 ...
  • 【SignalR全套系列】之在.Net Core 中實現SignalR實時通信 ...
  • Cgroup Freezer cgroup freezer對於批量啟動和停止任務集合的任務管理系統來說是很有用的,這個程式經常被用在HPC族上來調度訪問。cgroup freezer使用cgroups來描述被批處理任務管理系統啟動和停止的任務集合。他也提供了方法來啟動和停止任務。 cgroup fr ...
  • Block IO Controller 1 概覽 cgroup子系統blkio實現了block io控制器。無論是對存儲結構上的葉子節點和還是中間節點,它對各種IO控制策略(proportional BW, max BW)都是必須的。設計規劃就是使用同樣的cgroup,基於blkio控制器的管理介面 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 一:虛擬機宿主機互ping不通 問題一:防火牆 略去,建議主機和宿主機都關閉防火牆,並關閉seLinux(Linux的安全系統) 問題二:網卡未生效 表現 輸入命令 ifcongig,若輸出的網卡信息不含inet [ip地址],則說明網卡未生效 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 由於我使用ubuntu20.04的火狐瀏覽器時,總是播放不了視頻。說是要下載Flash,但是我順著網址進去,發現並沒有linux版本的(也可能是我沒找到而已?)。於是一直放著沒管,看不了就看不了,真要看我就用筆記本的win10看好了。但是偶爾看到 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...