Linux-3.14.12記憶體管理筆記【構建記憶體管理框架(3)】

来源:https://www.cnblogs.com/linhaostudy/archive/2019/10/05/11625209.html
-Advertisement-
Play Games

此處接前文,分析free_area_init_nodes()函數最後部分,分析其末尾的迴圈: 這裡面的關鍵函數是free_area_init_node(),其入參find_min_pfn_for_node()用於獲取node節點中最低的記憶體頁框號。 而free_area_init_node()其實現 ...


此處接前文,分析free_area_init_nodes()函數最後部分,分析其末尾的迴圈:

for_each_online_node(nid) {

    pg_data_t *pgdat = NODE_DATA(nid);

    free_area_init_node(nid, NULL,

            find_min_pfn_for_node(nid), NULL);

    /* Any memory on that node */

    if (pgdat->node_present_pages)

        node_set_state(nid, N_MEMORY);

    check_for_memory(pgdat, nid);

}

這裡面的關鍵函數是free_area_init_node(),其入參find_min_pfn_for_node()用於獲取node節點中最低的記憶體頁框號。

而free_area_init_node()其實現:

【file:/mm/page_alloc.c】
void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
        unsigned long node_start_pfn, unsigned long *zholes_size)
{
    pg_data_t *pgdat = NODE_DATA(nid);
    unsigned long start_pfn = 0;
    unsigned long end_pfn = 0;
 
    /* pg_data_t should be reset to zero when it's allocated */
    WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
 
    pgdat->node_id = nid;
    pgdat->node_start_pfn = node_start_pfn;
    init_zone_allows_reclaim(nid);
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
    get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
#endif
    calculate_node_totalpages(pgdat, start_pfn, end_pfn,
                  zones_size, zholes_size);
 
    alloc_node_mem_map(pgdat);
#ifdef CONFIG_FLAT_NODE_MEM_MAP
    printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n",
        nid, (unsigned long)pgdat,
        (unsigned long)pgdat->node_mem_map);
#endif
 
    free_area_init_core(pgdat, start_pfn, end_pfn,
                zones_size, zholes_size);
}

該函數中,其中init_zone_allows_reclaim()用於計算評估記憶體管理區是否可回收以及合適的node節點數,如果非NUMA環境,則該函數為空。而基於CONFIG_HAVE_MEMBLOCK_NODE_MAP的配置下,接下來將是get_pfn_range_for_nid():

【file:/mm/page_alloc.c】
/**
 * get_pfn_range_for_nid - Return the start and end page frames for a node
 * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
 * @start_pfn: Passed by reference. On return, it will have the node start_pfn.
 * @end_pfn: Passed by reference. On return, it will have the node end_pfn.
 *
 * It returns the start and end page frame of a node based on information
 * provided by an arch calling add_active_range(). If called for a node
 * with no available memory, a warning is printed and the start and end
 * PFNs will be 0.
 */
void __meminit get_pfn_range_for_nid(unsigned int nid,
            unsigned long *start_pfn, unsigned long *end_pfn)
{
    unsigned long this_start_pfn, this_end_pfn;
    int i;
 
    *start_pfn = -1UL;
    *end_pfn = 0;
 
    for_each_mem_pfn_range(i, nid, &this_start_pfn, &this_end_pfn, NULL) {
        *start_pfn = min(*start_pfn, this_start_pfn);
        *end_pfn = max(*end_pfn, this_end_pfn);
    }
 
    if (*start_pfn == -1UL)
        *start_pfn = 0;
}

此函數主要是將記憶體node節點的起始和末尾頁框號返回給接下來的calculate_node_totalpages()來使用。

calculate_node_totalpages()實現:

【file:/mm/page_alloc.c】
static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
                        unsigned long node_start_pfn,
                        unsigned long node_end_pfn,
                        unsigned long *zones_size,
                        unsigned long *zholes_size)
{
    unsigned long realtotalpages, totalpages = 0;
    enum zone_type i;
 
    for (i = 0; i < MAX_NR_ZONES; i++)
        totalpages += zone_spanned_pages_in_node(pgdat->node_id, i,
                             node_start_pfn,
                             node_end_pfn,
                             zones_size);
    pgdat->node_spanned_pages = totalpages;
 
    realtotalpages = totalpages;
    for (i = 0; i < MAX_NR_ZONES; i++)
        realtotalpages -=
            zone_absent_pages_in_node(pgdat->node_id, i,
                          node_start_pfn, node_end_pfn,
                          zholes_size);
    pgdat->node_present_pages = realtotalpages;
    printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id,
                            realtotalpages);
}

其中zone_spanned_pages_in_node():

【file:/mm/page_alloc.c】
/*
 * Return the number of pages a zone spans in a node, including holes
 * present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
 */
static unsigned long __meminit zone_spanned_pages_in_node(int nid,
                    unsigned long zone_type,
                    unsigned long node_start_pfn,
                    unsigned long node_end_pfn,
                    unsigned long *ignored)
{
    unsigned long zone_start_pfn, zone_end_pfn;
 
    /* Get the start and end of the zone */
    zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
    zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
    adjust_zone_range_for_zone_movable(nid, zone_type,
                node_start_pfn, node_end_pfn,
                &zone_start_pfn, &zone_end_pfn);
 
    /* Check that this node has pages within the zone's required range */
    if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn)
        return 0;
 
    /* Move the zone boundaries inside the node if necessary */
    zone_end_pfn = min(zone_end_pfn, node_end_pfn);
    zone_start_pfn = max(zone_start_pfn, node_start_pfn);
 
    /* Return the spanned pages */
    return zone_end_pfn - zone_start_pfn;
}

其主要是統計node管理節點的記憶體跨度,該跨度不包括movable管理區的,裡面調用的adjust_zone_range_for_zone_movable()則是用於剔除movable管理區的部分。

另外的zone_absent_pages_in_node():

【file:/mm/page_alloc.c】
/* Return the number of page frames in holes in a zone on a node */
static unsigned long __meminit zone_absent_pages_in_node(int nid,
                    unsigned long zone_type,
                    unsigned long node_start_pfn,
                    unsigned long node_end_pfn,
                    unsigned long *ignored)
{
    unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type];
    unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
    unsigned long zone_start_pfn, zone_end_pfn;
 
    zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
    zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
 
    adjust_zone_range_for_zone_movable(nid, zone_type,
            node_start_pfn, node_end_pfn,
            &zone_start_pfn, &zone_end_pfn);
    return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
}

該函數主要用於計算記憶體空洞頁面數的。完了將會得到物理頁面總數併在calculate_node_totalpages()中將頁面總數列印出來:

image

再往下的mminit_verify_pageflags_layout()函數主要用於記憶體初始化調測使用的,由於未開啟CONFIG_DEBUG_MEMORY_INIT配置項,此函數為空。而setup_nr_node_ids()是用於設置記憶體節點總數的,此處如果最大節點數MAX_NUMNODES不超過1,則是空函數。

free_area_init_nodes()函數末了還有一個遍歷各個節點做初始化的操作,暫且留待後面再分析。


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

-Advertisement-
Play Games
更多相關文章
  • java當中JDBC當中請給出一個SQLServer DataSource and SingleTon例子 ...
  • 前言 上一章介紹了Docker通過多條命令創建啟動運行Docker容器,由此可見這樣一個個去創建單獨的容器也是相當麻煩的,比如要在某個複雜項目中用DB、緩存、消息等等,這樣我們還要去一個個再創建,為此這時候需要用上我們三劍客中的一員大將自動擋的( DockerCompose ). Compose 是 ...
  • SignalR是為了提供更方便的web交互響應式到推送式的解決方案。有了它之後可以實現客戶端直接調用服務端的方法並且獲得返回值 (客戶端可以是各種平臺,目前SignalR支持的語言版本有C#、java、javaScript、nodejs等),服務端也是可以調用客戶端的方法,通過這樣的方式實現了由原來 ...
  • 點這裡進入ABP開發手記目錄 效果預覽 至此,基於ABP的CURD(增刪改查)示例已完成,效果如下 登錄 首頁 查詢課程 新增課程 修改課程 刪除課程 階段總結 關鍵步驟: 領域層創建實體基礎設施層更新資料庫應用層創建應用服務展示層實現增刪改查 迴圈往複此步驟即可創建多個CURD頁面. ...
  • 背景 By 魯迅 By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex A53,雙核 3. 使用工具:Source Insight 3.5, Visio 1. 介紹 之前的系列記憶體管理文章基本上描述的是物理頁面的初始化過程,以及虛擬頁面到物理頁面的映射建立過程 ...
  • Elasticsearch 集群搭建 環境及軟體 centos7 elasticsearch 7.4.0 因為ES7已經內置了所需的java的JDK版本,因此在此不再介紹java安裝 ES7安裝方式使用RPM安裝方式。 es節點列表 | ip | 節點名 | | | | |192.168.1.100 ...
  • 一、中斷 由於某個事件的發生,CPU暫停當前正在執行的程式,轉而執行處理事件的一個程式。該程式執行完成後,CPU接著執行被暫停的程式。這個過程稱為中斷。(我正在捉泥鰍,但是我媽喊我回家吃飯,我必須回家吃飯,回家途中,發現泥鰍沒帶,回去把泥鰍帶回家,然後吃完飯繼續捉泥鰍!!!) 中斷是CPU處理外部突 ...
  • 舊電腦,原來使用的是win xp。隨著win及其支持的軟體的“成長”,電腦運行越來越慢了。一個操作需要很長的時間等待,終於,失去了耐心,換了新的電腦。 舊電腦棄置多年,留之無用,棄之可惜。偶發奇想,換Linux試一試。 經過幾天的百度,決定選用StartOS試一試。 一、下載StartOS 百度St ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...