Linux驅動技術(一) _記憶體申請

来源:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/11/6375811.html
-Advertisement-
Play Games

先上基礎,下圖是Linux的記憶體映射模型 1. 每一個進程都有自己的進程空間,進程空間的0 3G是用戶空間,3G 4G是內核空間 2. 每個進程的用戶空間不在同一個物理記憶體頁,但是所有的進程的內核空間對應同樣的物理地址 3. vmalloc分配的地址可以高端記憶體,也可以是低端記憶體 4. 0 896M ...


先上基礎,下圖是Linux的記憶體映射模型

  1. 每一個進程都有自己的進程空間,進程空間的0-3G是用戶空間,3G-4G是內核空間
  2. 每個進程的用戶空間不在同一個物理記憶體頁,但是所有的進程的內核空間對應同樣的物理地址
  3. vmalloc分配的地址可以高端記憶體,也可以是低端記憶體
  4. 0-896MB的物理地址是線性映射到物理映射區的。
  5. 內核參數和系統頁表都在TEXT_OFFSET保存,除了進程除了訪問自身的用戶空間對應的DRAM記憶體頁外,都要經過內核空間,也就是都要切換到內核態

記憶體動態申請

和應用層一樣,內核程式也需要動態的分配記憶體,不同的是,內核進程可以控制分配的記憶體是在用戶空間還是內核空間,前者可以用於給用戶空間的堆區分配記憶體,eg,用戶進程的用戶空間的malloc最終就會通過系統調用回調內核空間的記憶體分配函數,此時該記憶體分配函數就屬於該用戶進程,可以給在該用戶進程的堆區分配空間並返回,最終使得一個用會進程在自己的用戶空間獲得記憶體分配;後者只在內核空間分配,所以用戶進程不能直接訪問該空間,所以多用在滿足內核程式自身的記憶體需求,下麵是Linux內核空間申請記憶體常用API:

kmalloc - kfree

kmalloc申請的記憶體在物理記憶體上是連續的,他們與真實的物理地址只有一個固定的偏移,因此存在簡單的轉換關係。這個API 多用來申請不到一個page大小的記憶體。kmalloc的底層需要調用__get_free_pages,參數中表示記憶體類型的gtp_t flags正是這個函數的縮寫,常用的記憶體類型有GFP_USER,GFP_KERNEL,GFP_ATOMIC幾種。

  • GFP_USER表示為用戶空間頁分配記憶體,可以阻塞;

  • GFP_KERNEL是最常用的flag,註意,使用這個flag來申請記憶體時,如果暫時不能滿足,會引起進程阻塞,So,一定不要在中斷處理函數tasklet內核定時器等非進程上下文中使用GFP_KERNEL!!!
  • GFP_ATOMIC就可以用於上述三種情境,這個flag表示如果申請的記憶體不能用,則立即返回。

/**
 * kmalloc - allocate memory
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate.
 * The @flags argument may be one of:
 * %GFP_USER - Allocate memory on behalf of user.  May sleep.
 * %GFP_KERNEL - Allocate normal kernel ram.  May sleep.
 * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools.
 * 
 * For example, use this inside interrupt handlers.
 */
void *kmalloc(size_t size, gfp_t flags);
/**
 * kfree - free previously allocated memory
 * @objp: pointer returned by kmalloc.
 * If @objp is NULL, no operation is performed.
 */
void kfree(const void *objp);

同系列API還有

void *kzalloc(size_t size, gfp_t flags)    

__get_free_pages - free_pages

__get_free_pages()與kmalloc()一樣是物理連續的記憶體,這一系列函數是Linux內核中最底層的用於獲取空閑記憶體的方法,因為底層的buddy演算法都是以(2^n)×PAGE_SIZE來管理記憶體的,所以他們總是以頁為單位分配記憶體

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)  
void free_pages(unsigned long addr, unsigned int order)  

同系列API還有

unsigned long __get_free_page(gfp_t gfp)        
unsigned long get_zeroed_page(gfp_t gfp_mask)    
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
void free_page(unsigned long addr)  

vmalloc - vfree

vmalloc在虛擬記憶體空間給出一塊連續的記憶體區,實質上,這片連續的虛擬記憶體在物理記憶體中並不一定連續,所以vmalloc申請的虛擬記憶體和物理記憶體之間也就沒有簡單的換算關係,正因如此,vmalloc()通常用於分配遠大於__get_free_pages()的記憶體空間,它的實現需要建立新的頁表,此外還會調用使用GFP_KERN的kmalloc,so,一定不要在中斷處理函數tasklet內核定時器等非進程上下文中使用vmalloc!

/**     
 * vmalloc  -  allocate virtually contiguous memory
 * @size:          allocation size
 * Allocate enough pages to cover @size from the page level allocator and map them into contiguous kernel virtual space.
 */
void *vmalloc(unsigned long size)   

/**
 *      vfree  -  release memory allocated by vmalloc()
 *      @addr:          memory base address
 */
void vfree(const void *addr)  

同系列的API還有

/**
 * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
 * @size:          allocation size
 * Allocate enough 32bit PA addressable pages to cover @size from the page level allocator and map them into contiguous kernel virtual space.
 */
void *vmalloc_32(unsigned long size) 

slab緩存

我們知道,頁是記憶體映射的基本單位,但內核中很多頻繁創建的對象所需記憶體都不到一頁,此時如果仍然按照頁映射的方式,頻繁的進行分配和釋放就會造成資源的浪費,同時也會降低系統性能。為瞭解決的這樣的問題,內核引入了slab機制,使對象在前後兩次被使用時被分配在同一塊記憶體或同一類記憶體空間,且保留了基本的數據結構,就可以大大提高效率。kmalloc的底層即是使用slab演算法管理分配的記憶體的。註意,slab依然是以頁為單位進行映射,只是映射之後分割這些頁為相同的更小的單元,從而節省了記憶體。slab分配的單元不能小於32B或大於128K。

/**
 * kmem_cache_create - 創建slab緩存對象
 * @name:slab緩存區名字,
 * @size:slab分配的緩存區的每一個單元的大小
 * @align:緩存區記憶體的對齊方式,一般給0
 * @flags:控制分配的位掩碼,
 * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) to catch references to uninitialised memory.
 * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check for buffer overruns.
 * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware cacheline.  This can be beneficial if you're counting cycles as closely as davem.
 * %SLAB_CACHE_DMA - Use GFP_DMA memory
 * %SLAB_STORE_USER - Store the last owner for bug hunting
 *define SLAB_PANIC - Panic if kmem_cache_create() fails 
 */
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *))


/**
 * kmem_cache_alloc - Allocate an object from this cache. 
 * @cachep: The cache to allocate from.
 * @flags: See kmalloc().
 * The flags are only relevant if the cache has no available objects.
 */
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)  


/**
 * kmem_cache_free - Deallocate an object
 * @cachep: The cache the allocation was from.
 * @objp: The previously allocated object.
 * Free an object which was previously allocated from this cache.
 */
void kmem_cache_free(struct kmem_cache *cachep, void *objp)  


void kmem_cache_destroy(struct kmem_cache *s)  

範例

//創建slab對象
struct kmem_cache_t *xj_sbcache;
xj_sbcache = kmem_cache_create("xjslab",sizeof(struct xj_unit_t),0,SLAB_CACHE_DMA|SLAB_PANIC,NULL,NULL);

//分配slab緩存
struct xj_unit_t *xj_unit;
xj_unit = kmem_cache_alloc(xj_sbcache,GFP_KERNEL);

/* 使用slab緩存 */

/* 釋放slab緩存 */
kmem_cache_free(xj_sbcache, xj_unit);

/* 銷毀slab緩存 */
kmem_cache_destroy(xj_sbcache);

記憶體池

除了slab機制,內核還提供了傳統的記憶體池機制來管理小塊記憶體的分配。記憶體池主要是用來解決可能出現的記憶體不足的情況,因為一個記憶體池在創建的時候就已經分配好了一記憶體,當我們用mempool_alloc向一個已經創建好的記憶體池申請申請記憶體時,該函數首先會嘗試回調記憶體池創建時的分配記憶體函數,如果已經沒有記憶體可以分配,他就會使用記憶體池創建時預先分配的記憶體,這樣就可以避免因為無記憶體分配而陷入休眠,當然,如果預分配的記憶體也已經使用完畢,還是會陷入休眠。slab機制的目的是提高記憶體使用率以及記憶體管理效率,記憶體池的目的是避免記憶體的分配失敗。下麵是內核中提供的關於記憶體池的API

/**     
 * mempool_create - create a memory pool
 * @min_nr:    the minimum number of elements guaranteed to be  allocated for this pool.
 * @alloc_fn:  user-defined element-allocation function.
 * @free_fn:   user-defined element-freeing function.
 * @pool_data: optional private data available to the user-defined functions.
 *              
 * this function creates and allocates a guaranteed size, preallocated memory pool. The pool can be used from the mempool_alloc() and mempool_free() functions. 
 * This function might sleep. Both the alloc_fn() and the free_fn() functions might sleep - as long as the mempool_alloc() function is not called from IRQ contexts.
 */
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data)

/**     
 * mempool_alloc - allocate an element from a specific memory pool
 * @pool:      pointer to the memory pool which was allocated via mempool_create().
 * @gfp_mask:  the usual allocation bitmask.
 * this function only sleeps if the alloc_fn() function sleeps or returns NULL. Note that due to preallocation, this function never* fails when called from process contexts. (it might fail if called from an IRQ context.)
 */     
void * mempool_alloc(mempool_t *pool, gfp_t gfp_mask)    

/**
 * mempool_free - return an element to the pool.
 * @element:   pool element pointer.
 * @pool:      pointer to the memory pool which was allocated via mempool_create().
 *
 * this function only sleeps if the free_fn() function sleeps.
 */     
void mempool_free(void *element, mempool_t *pool)    

/**
 * mempool_destroy - deallocate a memory pool
 * @pool:      pointer to the memory pool which was allocated via mempool_create().
 *
 * Free all reserved elements in @pool and @pool itself.  This function only sleeps if the free_fn() function sleeps.
 */     
void mempool_destroy(mempool_t *pool)  

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

-Advertisement-
Play Games
更多相關文章
  • 網上下載的軟體,如果來自身份不明的開發者,在MAC上打開時會提示無法確認開發者的身份,在網上找到了一篇嘗試解決的文章,文章鏈接地址為http://jingyan.baidu.com/article/f71d60377960651ab741d140.html,原文內容如下: 使用 Mac 電腦系統的小 ...
  • 非同步通知的全稱是"信號驅動的非同步IO",通過"信號"的方式,放期望獲取的資源可用時,驅動會主動通知指定的應用程式,和應用層的"信號"相對應,這裡使用的是信號" SIGIO "。操作步驟是 1. 應用層程式將自己註冊為接收來自設備文件的SIGIO信號的進程 2. 驅動實現相應的介面,以期具有向所有註冊 ...
  • 第十三節 定時任務補充 標簽(空格分隔): Linux實戰教學筆記 [更多資料點我查看][1] 1,生產環境常用Crontab專業實例 1.1書寫crontab定時任務多個基本要領 1.1.1 規範定時任務兩例 例1:每分鐘列印一次自己的名字拼音全拼到“/server/log/自己的名字命名的文件” ...
  • 首先下載 Gradle 通過官網進行下載 https://gradle.org 下載的文件名可能是 gradle 3.3 bin.zip 解壓 將此文件解壓到任意位置,如解壓到 /usr/local 下麵 sudo unzip d /usr/local gradle 3.3 bin.zip 設置環境 ...
  • awk: 強大的文本處理工具,擅長對日誌文件進行分析; 不僅用於Linux,也是任何環境中現在的功能最強大的數據處理引擎; 語法說明: awk '{pattern + action}' {filenames} pattern:指在數據中要查找的內容; action:指要操作的指令。 {}可以對一系列 ...
  • DMA即Direct Memory Access,是一種允許外設直接存取記憶體數據而沒有CPU參與的技術,當外設對於該塊記憶體的讀寫完成之後,DMAC通過中斷通知CPU,這種技術多用於對數據量和數據傳輸速度都有很高要求的外設控制,比如顯示設備等。 DMA和Cache一致性 我們知道,為了提高系統運行效率 ...
  • ARM是對記憶體空間和IO空間統一編址的,所以,通過讀寫SFR來控制硬體也就變成了通過讀寫相應的SFR地址來控制硬體。這部分地址也被稱為 I/O記憶體 。x86中對I/O地址和記憶體地址是分開編址的,這樣的IO地址被稱為 I/O埠 。本文只討論IO記憶體的訪問 IO記憶體訪問流程 我們知道,為了管理最重要的 ...
  • Saltstack是Python開發的,上千台的伺服器都可以管理。 運維重覆性工作:系統安裝、環境部署、添加監控、代碼發佈(基於git或svn二次開發)、項目遷移、計劃任務。 salt是一個新的基礎平臺管理工具。只需花費數分鐘即可運行起來,擴展性足以支撐管理上萬台伺服器,數秒即可完成數據傳遞。 sa... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...