【原創】(十二)Linux記憶體管理之vmap與vmalloc
背景
Read the fucking source code!
--By 魯迅A picture is worth a thousand words.
--By 高爾基
說明:
- Kernel版本:4.14
- ARM64處理器,Contex-A53,雙核
- 使用工具: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_area
中vm
欄位是struct vm_struct
結構,用於管理虛擬地址和物理頁之間的對映關係,可以將struct vm_struct
構成一個連結串列,維護多段對映。
關係如下圖:
2.2 紅黑樹
紅黑樹,本質上是一種二叉查詢樹,它在二叉查詢樹的基礎上增加了著色相關的性質,提升了紅黑樹在查詢,插入,刪除時的效率。在紅黑樹中,節點已經進行排序,對於每個節點,左側的的元素都在節點之前,右側的元素都在節點之後。
- 每個節點不是紅就是黑;
- 紅黑樹的根必須是黑;
- 紅節點的子節點必須為黑;
- 從節點到子節點的每個路徑都包含相同數量的黑節點,統計黑節點個數時,空指標也算黑節點;
定義如下:
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
。
直接分析呼叫流程:
從過程中可以看出,vmalloc
和vmap
的操作,大部分的邏輯操作是一樣的,比如從VMALLOC_START ~ VMALLOC_END
區域之間查詢並分配vmap_area
, 比如對虛擬地址和物理頁框進行對映關係的建立。不同之處,在於vmap
建立對映時,page
是函式傳入進來的,而vmalloc
是通過呼叫alloc_page
介面向Buddy System申請分配的。
vmalloc VS kmalloc
到現在,我們應該能清楚vmalloc
和kmalloc
的差異了吧,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記憶體管理之vmap與vmalloc
背景 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 Learning【NLP】(十二)
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
【Git之窗】(十四)git 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.
【linux】Valgrind工具集詳解(十二):DHAT:動態堆分析器
一、概述 DHAT動態堆分析器。Massif(堆分析器)是在程式結束後輸出分析結果,而DHAT是實時輸出結果,所以叫做動態堆分析器。Massif只記錄堆記憶體的申請和釋放,DHAT還會分析堆空間的使用率、使用週期等資訊。 DHAT的功能:它首先記錄在堆上分配的塊,通過分析每次記憶體訪