1. 程式人生 > >【原創】(十二)Linux記憶體管理之vmap與vmalloc

【原創】(十二)Linux記憶體管理之vmap與vmalloc

背景

  • 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. 概述

在之前的系列文章中,分析到了Buddy System的頁框分配,Slub分配器的小塊記憶體物件分配,這些分配的地址都是實體記憶體連續的。當記憶體碎片後,連續實體記憶體的分配就會變得困難,可以使用vmap機制,將不連續的實體記憶體頁框對映到連續的虛擬地址空間中。vmalloc

的分配就是基於這個機制來實現的。

還記得下邊這張圖嗎?

vmap/vmalloc的區域就是在VMALLOC_START ~ VMALLOC_END之間。

開啟探索之旅吧。

2. 資料結構

2.1 vmap_area/vm_struct

這兩個資料結構比較簡單,直接上程式碼:

struct vm_struct {
    struct vm_struct    *next;
    void            *addr;
    unsigned long       size;
    unsigned long       flags;
    struct page     **pages;
    unsigned int        nr_pages;
    phys_addr_t     phys_addr;
    const void      *caller;
};

struct vmap_area {
    unsigned long va_start;
    unsigned long va_end;
    unsigned long flags;
    struct rb_node rb_node;         /* address sorted rbtree */
    struct list_head list;          /* address sorted list */
    struct llist_node purge_list;    /* "lazy purge" list */
    struct vm_struct *vm;
    struct rcu_head rcu_head;
};

struct vmap_area用於描述一段虛擬地址的區域,從結構體中va_start/va_end也能看出來。同時該結構體會通過rb_node掛在紅黑樹上,通過list掛在連結串列上。
struct vmap_areavm欄位是struct vm_struct結構,用於管理虛擬地址和物理頁之間的對映關係,可以將struct vm_struct構成一個連結串列,維護多段對映。

關係如下圖:

2.2 紅黑樹

紅黑樹,本質上是一種二叉查詢樹,它在二叉查詢樹的基礎上增加了著色相關的性質,提升了紅黑樹在查詢,插入,刪除時的效率。在紅黑樹中,節點已經進行排序,對於每個節點,左側的的元素都在節點之前,右側的元素都在節點之後。

紅黑樹必須滿足以下四條規則:

  1. 每個節點不是紅就是黑;
  2. 紅黑樹的根必須是黑;
  3. 紅節點的子節點必須為黑;
  4. 從節點到子節點的每個路徑都包含相同數量的黑節點,統計黑節點個數時,空指標也算黑節點;

定義如下:

struct rb_node {
    unsigned long  __rb_parent_color;
    struct rb_node *rb_right;
    struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
    /* The alignment might seem pointless, but allegedly CRIS needs it */

由於核心會頻繁的進行vmap_area的查詢,紅黑樹的引入就是為了解決當查詢數量非常多時效率低下的問題,在紅黑樹中,搜尋元素,插入,刪除等操作,都會變得非常高效。至於紅黑樹的演算法操作,本文就不再深入分析,知道它的用途即可。

3. vmap/vunmap分析

3.1 vmap

vmap函式,完成的工作是,在vmalloc虛擬地址空間中找到一個空閒區域,然後將page頁面陣列對應的實體記憶體對映到該區域,最終返回對映的虛擬起始地址。

整體流程如下:

操作流程比較簡單,來一個樣例分析,就清晰明瞭了:

vmap呼叫中,關鍵函式為alloc_vmap_area,它先通過vmap_area_root二叉樹來查詢第一個區域first vm_area,然後根據這個first vm_area去查詢vmap_area_list連結串列中滿足大小的空間區域。

alloc_vmap_area函式中,有幾個全域性的變數:

static struct rb_node *free_vmap_cache;
static unsigned long cached_hole_size;
static unsigned long cached_vstart;
static unsigned long cached_align;

用於快取上一次分配成功的vmap_area,其中cached_hole_size用於記錄快取vmap_area對應區域之前的空洞的大小。快取機制當然也是為了提高分配的效率。

3.2 vunmap

vunmap執行的是跟vmap相反的過程:從vmap_area_root/vmap_area_list中查詢vmap_area區域,取消頁表對映,再從vmap_area_root/vmap_area_list中刪除掉vmap_area,頁面返還給夥伴系統等。由於對映關係有改動,因此還需要進行TLB的重新整理,頻繁的TLB重新整理會降低效能,因此將其延遲進行處理,因此稱為lazy tlb

來看看逆過程的流程:

4. vmalloc/vfree分析

4.1 vmalloc

vmalloc用於分配一個大的連續虛擬地址空間,該空間在物理上不連續的,因此也就不能用作DMA緩衝區。vmalloc分配的線性地址區域,在文章開頭的圖片中也描述了:VMALLOC_START ~ VMALLOC_END

直接分析呼叫流程:

從過程中可以看出,vmallocvmap的操作,大部分的邏輯操作是一樣的,比如從VMALLOC_START ~ VMALLOC_END區域之間查詢並分配vmap_area, 比如對虛擬地址和物理頁框進行對映關係的建立。不同之處,在於vmap建立對映時,page是函式傳入進來的,而vmalloc是通過呼叫alloc_page介面向Buddy System申請分配的。

  • vmalloc VS kmalloc
    到現在,我們應該能清楚vmallockmalloc的差異了吧,kmalloc會根據申請的大小來選擇基於slub分配器或者基於Buddy System來申請連續的實體記憶體。而vmalloc則是通過alloc_page申請order = 0的頁面,再對映到連續的虛擬空間中,實體地址不連續,此外vmalloc可以休眠,不應在中斷處理程式中使用。
    vmalloc相比,kmalloc使用ZONE_DMA和ZONE_NORMAL空間,效能更快,缺點是連續實體記憶體空間的分配容易帶來碎片問題,讓碎片的管理變得困難。

4.2 vfree

直接上程式碼:

void vfree(const void *addr)
{
    BUG_ON(in_nmi());

    kmemleak_free(addr);

    if (!addr)
        return;
    if (unlikely(in_interrupt()))
        __vfree_deferred(addr);
    else
        __vunmap(addr, 1);
}

如果在中斷上下文中,則推遲釋放,否則直接呼叫__vunmap,所以它的邏輯基本和vunmap一致,不再贅述了。

相關推薦

原創Linux記憶體管理vmapvmalloc

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理page fault處理

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理RMAP

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理CMA

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理slub分配器

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

深度學習筆記——理論推導Structured LearningNLP

Language Technology Meaning of Word(一個vector表示一個word) Predicting the next word 給一串sequence of words,預測下一個單詞 我們現在要做的就是將wi

GANs學習筆記SAGAN

3.1 SAGAN解決的問題 前篇我們說到用深度卷積網路能夠提升GANs生成高解析度圖片的細節,但是由於卷積網路的區域性感受野的限制,如果要生成大範圍相關(Long-range dependency)的區域,卷積網路就會出現問題。譬如說在生成人臉圖片時,是非常

原創十三Linux記憶體管理vma/malloc/mmap

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

Linux內核設計實現》讀書筆記- 內存管理

enable vmalloc 緩沖 turn lean png border 編譯 不一致 內核的內存使用不像用戶空間那樣隨意,內核的內存出現錯誤時也只有靠自己來解決(用戶空間的內存錯誤可以拋給內核來解決)。 所有內核的內存管理必須要簡潔而且高效。 主要內容: 內

linux下hadoop安裝配置

-i host 配置文件 localhost mapreduce stat reboot app table 1.準備Linux環境 1.1關閉防火墻 #查看防火墻狀態 service iptables status #關閉防火墻 service iptables

耳朵——linux靜態IP設定

linux設定靜態ip: linux系統的ip的設定與網絡卡有關linux系統的網絡卡在/etc/sysconfig/network-script/目錄下。 以本機為例網絡卡資訊就放在這個目錄下的ifcfg.ens33檔案裡 [[email prote

Gitgit pull 衝突的解決避免

問題如圖: 分析:       1.專案分支:master和fcarloan_branch_V1.0.4,一個是主分支,一個是“電銷分支”       2.現在需要新建一個解決“is_rightnow_bill”問題的分支,我在本地checkout -b 一個新分支,如上(1

SpringCloud:超時機制和斷路器及 Hystrix簡單實踐

  上篇文章我們配置了Eureka叢集,實現了高可用。在微服務框架中,一個服務消費者可能是其他服務消費者的提供者,而當低層次的服務提供者出現問題時,會導致系統資源被耗盡。出現雪崩效應。 Hystri

SpringCloud:Feign對Hystrix的支援 fallbackFactory

  前面的文章中提到了fallback,這裡我們描述一個它的增強版。fallbackFactory。都是實現斷路器的功能。 UserFeignClient package com.dynam

SpringCloud:Zuul的基本應用,反向代理和負載均衡

  Router and Filter: Zuul。 Zuul is a JVM based router and server side load balancer by Netflix。   Zu

深入理解 Java 虛擬機器Java 記憶體模型執行緒

執行緒安全 Java 語言中的執行緒安全 根據執行緒安全的強度排序,Java 語言中各種操作共享的資料可以分為 5 類:不可變、絕對執行緒安全、相對執行緒安全、執行緒相容、執行緒對立。 不可變 不可變的物件一定是執行緒安全的,如果共享資料是一個基本資料型別,那麼

Linux初級運維——Linux軟體管理

一、軟體包管理     1、應用程式:         程式,Architecture      C語言:原始碼-->(編譯

Java架構學習java記憶體結構&新生代&老年代&JVM引數調優&堆記憶體引數配置&解決堆疊溢位

JVM引數調優與垃圾回收機制 一、java記憶體結構 Java記憶體模型:是多執行緒裡面的,jmm與執行緒可見性有關 Java記憶體結構:是JVM虛擬機器儲存空間。 Java記憶體結構圖 Java記憶體機構分為:方法區、java堆、棧、本地

從零寫一個編譯器:程式碼生成生成邏輯

專案的完整程式碼在 C2j-Compiler 前言 在上一篇解釋完了一些基礎的Java位元組碼指令後,就可以正式進入真正的程式碼生成部分了。但是這部分先說的是程式碼生成依靠的幾個類,也就是用來生成指令的操作。 這一篇用到的檔案都在codegen下: Directive.java Instruction.

linuxValgrind工具集詳解:DHAT:動態堆分析器

一、概述 DHAT動態堆分析器。Massif(堆分析器)是在程式結束後輸出分析結果,而DHAT是實時輸出結果,所以叫做動態堆分析器。Massif只記錄堆記憶體的申請和釋放,DHAT還會分析堆空間的使用率、使用週期等資訊。 DHAT的功能:它首先記錄在堆上分配的塊,通過分析每次記憶體訪