【原創】(六)Linux記憶體管理 - zoned page frame allocator - 1

来源:https://www.cnblogs.com/LoyenWang/archive/2019/10/06/11626237.html
-Advertisement-
Play Games

背景 By 魯迅 By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex A53,雙核 3. 使用工具:Source Insight 3.5, Visio 1. 介紹 之前的系列記憶體管理文章基本上描述的是物理頁面的初始化過程,以及虛擬頁面到物理頁面的映射建立過程 ...


背景

  • Read the fucking source code! --By 魯迅
  • A picture is worth a thousand words. --By 高爾基

說明:

  1. Kernel版本:4.14
  2. ARM64處理器,Contex-A53,雙核
  3. 使用工具:Source Insight 3.5, Visio

1. 介紹

之前的系列記憶體管理文章基本上描述的是物理頁面的初始化過程,以及虛擬頁面到物理頁面的映射建立過程,從這篇文章開始,真正要涉及到頁面的分配了。接下來的文章會圍繞著分區頁框分配器(zoned page frame allocator)來展開,其中會包含大家熟知的Buddy System分析。

本文會先圍繞著涉及到的數據結構,以及大體的流程做一個整體的分析,後續會針對這個流程中的細節進行更詳細的拆解,我已經迫不及待了。

2. 數據結構

2.1 概述

先回顧一下(五)Linux記憶體管理zone_sizes_init的數據結構圖:

上述的結構體,描述的是下麵這張圖:

Node ---> ZONE ---> Page的組織關係,其中Buddy System中,頁面都是以2的次冪來組織成鏈表,比如free_area[0],對應的是1個page鏈表,其中又根據不同的MIGRATE_xxxx類型來組織,如下圖:

ARM64MAX_ORDER預設值為11,PAGE_SIZE=4K,因此總共有0 ~ 1011個鏈表數組,鏈表中的連續的頁面為2^0 ~ 2^10,對應大小為4K ~ 4M

可以通過cat /proc/pagetypeinfo來查看下系統的頁面信息,如下圖:

可以通過cat /proc/zoneinfo來查看NodeZONE計數信息:

2.2 Migrate類型

從上邊的圖中可以看到MIGRATE_xxx不同的遷移類型,表明頁面的移動屬性,併在可能的情況下通過將相同屬性的頁面分組在一起來抑制記憶體的連續碎片。

enum migratetype {
    MIGRATE_UNMOVABLE,
    MIGRATE_MOVABLE,
    MIGRATE_RECLAIMABLE,
    MIGRATE_PCPTYPES,   /* the number of types on the pcp lists */
    MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
#ifdef CONFIG_CMA
    /*
     * MIGRATE_CMA migration type is designed to mimic the way
     * ZONE_MOVABLE works.  Only movable pages can be allocated
     * from MIGRATE_CMA pageblocks and page allocator never
     * implicitly change migration type of MIGRATE_CMA pageblock.
     *
     * The way to use it is to change migratetype of a range of
     * pageblocks to MIGRATE_CMA which can be done by
     * __free_pageblock_cma() function.  What is important though
     * is that a range of pageblocks must be aligned to
     * MAX_ORDER_NR_PAGES should biggest page be bigger then
     * a single pageblock.
     */
    MIGRATE_CMA,
#endif
#ifdef CONFIG_MEMORY_ISOLATION
    MIGRATE_ISOLATE,    /* can't allocate from here */
#endif
    MIGRATE_TYPES
};
  • MIGRATE_UNMOVABLE:無法移動和檢索的類型,用於內核分配的頁面,I/O緩衝區,內核堆棧等;
  • MIGRATE_MOVABLE:當需要大的連續記憶體時,通過移動當前使用的頁面來儘可能防止碎片,用於分配用戶記憶體;
  • MIGRATE_RECLAIMABLE:當沒有可用記憶體時使用此類型;
  • MIGRATE_HIGHATOMIC:減少原子分配請求無法進行高階頁面分配的可能,內核會提前準備一個頁面塊;
  • MIGRATE_CMA:頁面類型由CMA記憶體分配器單獨管理;
  • MIGRATE_ISOLATE:內核會暫時更改為這種類型,以遷移使用中的系列活動頁面;

2.3 __GFP_xxx請求標誌(gfp_mask)

__GFP_xxx為內部使用的標誌,在include/linux/gfp.h文件中,外部不應該使用這些Flag,這些標誌在頁面申請的時候使用,其中GFP表示get free page

羅列部分如下:

  • __GFP_DMA:請求在ZONE_DMA區域中分配頁面;
  • __GFP_HIGHMEM:請求在ZONE_HIGHMEM區域中分配頁面;
  • __GFP_MOVABLEZONE_MOVALBE可用時在該區域分配頁面,同時表示頁面分配後可以在記憶體壓縮時進行遷移,也能進行回收;
  • __GFP_RECLAIMABLE:請求分配到可恢復頁面;
  • __GFP_HIGH:高優先順序處理請求;
  • __GFP_IO:請求在分配期間進行I/O操作;
  • __GFP_FS:請求在分配期間進行文件系統調用;
  • __GFP_ZERO:請求將分配的區域初始化為0;
  • __GFP_NOFAIL:不允許請求失敗,會無限重試;
  • __GFP_NORETRY:請求不重試記憶體分配請求;

2.4 ALLOC_xxxx分配標誌(alloc_flags)

分配標誌定義在mm/internal.h文件中,在頁面的分配函數中與gfp_mask分開使用,這些標誌時用於內部函數的分配。

  • ALLOC_WMARK_MIN:僅在最小水位water mark及以上限制頁面分配;
  • ALLOC_WMARK_LOW:僅在低水位water mark及以上限制頁面分配;
  • ALLOC_WMARK_HIGH:僅在高水位water mark及以上限制頁面分配;
  • ALLOC_HARDER:努力分配,一般在gfp_mask設置了__GFP_ATOMIC時會使用;
  • ALLOC_HIGH:高優先順序分配,一般在gfp_mask設置了__GFP_HIGH時使用;
  • ALLOC_CPUSET:檢查是否為正確的cpuset;
  • ALLOC_CMA:允許從CMA區域進行分配;

2.5 struct alloc_context

在頁面分配的過程中,有一個結構叫struct alloc_context,這個結構用於存儲各個函數之間傳遞的參數。這種思想在平時的coding中是可以去借鑒的,比如有些人寫代碼很喜歡用全局變數,改成這種context的形式,在各個函數之間傳遞顯得更為優雅。直接看代碼吧:

/*
 * Structure for holding the mostly immutable allocation parameters passed
 * between functions involved in allocations, including the alloc_pages*
 * family of functions.
 *
 * nodemask, migratetype and high_zoneidx are initialized only once in
 * __alloc_pages_nodemask() and then never change.
 *
 * zonelist, preferred_zone and classzone_idx are set first in
 * __alloc_pages_nodemask() for the fast path, and might be later changed
 * in __alloc_pages_slowpath(). All other functions pass the whole strucure
 * by a const pointer.
 */
struct alloc_context {
    struct zonelist *zonelist;
    nodemask_t *nodemask;
    struct zoneref *preferred_zoneref;
    int migratetype;
    enum zone_type high_zoneidx;
    bool spread_dirty_pages;
};
  • zonelist:用於分配頁面的區域列表;
  • nodemask:指定Node,如果沒有指定,則在所有節點中進行分配;
  • preferred_zone:指定要在快速路徑中首先分配的區域,在慢路徑中指定了zonelist中的第一個可用區域;
  • migratetype:要分配的遷移頁面類型;
  • high_zoneidx:將分配限製為小於區域列表中指定的高區域;
  • spread_dirty_pages:臟區平衡相關;

3. build_all_zonelists

在上篇文章中描述到各個zone,實際上各個zone最終組織起來是在build_all_zonelists函數中實現的:

整體完成的工作也比較簡單,將所有Node中可用的zone全部添加到各個Node中的zonelist中,也就是對應的struct pglist_data結構體中的struct zonelist node_zonelists欄位。

這一步之後,準備工作基本就緒,進行頁面申請的工作就可以開始了。

4. alloc_pages

下麵的流程開始真正的頁面申請了,在內部的實現中通過__alloc_pages來實現的:

在頁面分配時,有兩種路徑可以選擇,如果在快速路徑中分配成功了,則直接返回分配的頁面;快速路徑分配失敗則選擇慢速路徑來進行分配。

4.1 Fast Path

快速路徑分配,是通過get_page_from_freelist來完成的,具體的流程及分析如下圖所示:

4.2 Slow Path

慢速路徑分配,最終也會調用get_page_from_freelist,流程分析如下:


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

-Advertisement-
Play Games
更多相關文章
  • 併發隊列: 在併發隊列中,JDK有兩套實現: ConcurrentLinkedQueue:非阻塞式隊列 BlockingQueue:阻塞式隊列 阻塞式隊列非阻塞式隊列的區別: 阻塞式隊列入列操作的時候,如果超出隊列總數,這個時候會進行等待;在出列的時候,如果隊列為空,也會等待 非阻塞無論如何都不等待 ...
  • 開發:開發語言: 1.高級語言:Python Java、PHP C# Go ruby C++... 》 位元組碼 2.低級語言:C、彙編 》 機器碼語言之間的對比: 1.PHP類:適用於寫網頁,局限性 2.Python Java: 及可以寫網頁 也可以寫後臺功能 Python執行效率低,開發效率高 J ...
  • #include<stdio.h>#include<stdlib.h>#define MAX 100 typedef struct bNode{ double no; char name[MAX]; double price; struct bNode * next;}bNode,*bLnode; ...
  • 將數字以字元串輸出函數repr(): temp = 42 print = "Hello," + repr(temp) 註:在python3.0以前可使用反引號``實現,但之後便不再支持,如: 註:還可以使用str()實現,原理就是數值類型轉換。函數str() 用於將值轉化為適於人閱讀的形式,而rep ...
  • java當中JDBC當中請給出一個SQLServer DataSource and SingleTon例子 ...
  • 前言 上一章介紹了Docker通過多條命令創建啟動運行Docker容器,由此可見這樣一個個去創建單獨的容器也是相當麻煩的,比如要在某個複雜項目中用DB、緩存、消息等等,這樣我們還要去一個個再創建,為此這時候需要用上我們三劍客中的一員大將自動擋的( DockerCompose ). Compose 是 ...
  • SignalR是為了提供更方便的web交互響應式到推送式的解決方案。有了它之後可以實現客戶端直接調用服務端的方法並且獲得返回值 (客戶端可以是各種平臺,目前SignalR支持的語言版本有C#、java、javaScript、nodejs等),服務端也是可以調用客戶端的方法,通過這樣的方式實現了由原來 ...
  • 點這裡進入ABP開發手記目錄 效果預覽 至此,基於ABP的CURD(增刪改查)示例已完成,效果如下 登錄 首頁 查詢課程 新增課程 修改課程 刪除課程 階段總結 關鍵步驟: 領域層創建實體基礎設施層更新資料庫應用層創建應用服務展示層實現增刪改查 迴圈往複此步驟即可創建多個CURD頁面. ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...