zephyr 系統 記憶體池使用方法

2021-08-07 16:26:46 字數 2622 閱讀 6189

記憶體池(memory pool)是乙個核心物件,它允許從指定的記憶體區域上動態地分配記憶體塊(memory block)。同乙個記憶體池中的記憶體塊的大小是不固定的,這樣可以減小由於不同的應用程式需要為大小不同的資料結構分配不同的儲存空間所造成的浪費。記憶體池使用「夥伴(buddy)記憶體分配」演算法,它可以高效地將大塊記憶體分割為小塊記憶體。此外,它還可以在最大限度減小記憶體碎片的前提下,高效地分配和釋放不小不同的記憶體塊。

可以定義任意數量的記憶體池。每個記憶體池通過其記憶體位址進行引用。

記憶體池的關鍵屬性包括:

記憶體片的 buffer 必須 n 位元組對齊,其中 n 是大於 2 的 2 的整數次冪(例如 4,8,16…)。為了保證 buffer 中的所有記憶體塊都對齊到這個邊界,塊的大小必須是 n 的整數倍。

當執行緒需要記憶體塊時,它只需要從乙個記憶體池中申請。申請成功後,由執行緒提供的塊描述符的data字段表示該記憶體塊的起始位址。當執行緒使用完記憶體塊後,它必須將其釋放給記憶體池,讓其可以重複利用。

如果沒有找到所期望的記憶體塊,執行緒可以等待,直到某個塊可用。多個執行緒可以同時等待某個空的記憶體池;當某個記憶體塊可用時,它會被分配給優先順序最高的、等待時間最久的執行緒使用。

與堆不同的是,如果有需要,可以定義多個記憶體片。例如不同的應用程式可以利用不同的記憶體池。這樣可以阻止某個應用程式「綁架」所有資源。

記憶體池的 buffer 是乙個陣列,陣列的元素的大小是塊的最大尺寸,這樣能保證塊與塊之間沒有空間被浪費。每個「第 0 級」的塊是乙個 quad-block,(如果有需要)可以被分為四個小的大小相等的「第 1 級」塊。類似地,每個第 1 級塊也是 quad-block,也可以被分為四個小的大小相等的「第 2 級」塊。依次類推。因此,每個記憶體塊都可以遞迴地分為四分之一的小塊,知道小塊的尺寸不滿足塊最小尺寸。

記憶體池通過乙個叫做 塊集(block set) 的資料結構來跟蹤它的 buffer 空間的分割槽情況。記憶體池為所支援的每乙個劃分等級或者每乙個塊尺寸都維持了乙個塊集。每個塊集使用乙個叫做 quad-block 狀態 的資料結構的陣列來跟蹤它所關聯的尺寸的所有空閒塊。

當應用程式請求乙個記憶體塊時,記憶體池首先會判斷最小塊的尺寸是否滿足請求,並檢查其相應的塊集。如果塊集包含有乙個空閒塊,它會將該塊標記為以使用,然後分配過程就結束了。如果該塊集不包含空閒塊,記憶體池將嘗試將乙個更大尺寸的空閒塊分類成小的塊,或者將小塊合併為大的塊。如果不能建立這樣的塊,則分配失敗。

記憶體池的塊合併和**過程是非常高效的,但是它採用的是遞迴演算法,因此很容易產生顯著的開銷。此外,合併演算法不能將大小不同的相鄰塊結合在一起,也不能合併不屬於同乙個父 quad-block 的尺寸相同的相鄰塊。因此,使用記憶體池時依然會遇到碎片問題。

當應用程式釋放乙個已分配的記憶體塊時,僅僅會在該記憶體塊所關聯塊集中將其標記為空閒。記憶體池不會嘗試合併最近釋放的塊,這樣的好處是可以很方便地在其已存在的組織上進行重分配。

使用型別為struct k_mem_pool的變數可以定義乙個記憶體池。不過,由於記憶體池也需要大量的尺寸可變的資料結構來代表它的塊集合和它的 quad-block 的狀態,核心不支援在執行時動態地定義記憶體池。記憶體池只能使用k_mem_pool_define在編譯時進行定義和初始化。

下面的**定義並初始化了乙個記憶體池,這個記憶體池有三個大小為 4096 位元組的塊。這些塊也可以被劃分為最小為 64 位元組的 4 位元組對齊的子塊。(也就是說,記憶體池支援的塊大小是 4096、1024、256 和 64 位元組。)注意,該巨集定義了記憶體池的所有資料結構和它的 buffer。

k_mem_pool_define(my_pool, 

64,

4096,

3, 4);

函式k_mem_pool_alloc()用於分配記憶體塊。

下面的**會先等待 100 毫秒,以拿到乙個 200 位元組的可以記憶體塊,然後將其填充為零。如果沒有獲得合適的記憶體塊,**會列印乙個警告資訊。

注意,應用程式實際會接收到乙個大小為 256 位元組的記憶體塊,因為這是記憶體池所支援的最接近的尺寸。

struct

k_mem_block

block;

if (k_mem_pool_alloc(&my_pool, &block,

200,

100) ==

0))

else

函式k_mem_pool_free()用於釋放記憶體塊。

下面的**基於上面的例程之上,它申請了 75 位元組的記憶體塊,並在不再使用時釋放。(基於安全考慮,實際上會從堆記憶體池使用 256 位元組的記憶體塊。)

struct

k_mem_block

block;

k_mem_pool_alloc(&my_pool, &block,

75, k_forever);

...

/* use memory block */

k_mem_pool_free(&block);

當需要分配大小不固定的記憶體時,可以使用記憶體池。

當乙個執行緒需要給另乙個執行緒傳送大量的資料時,可以使用記憶體池,這樣可以避免不必要的資料拷貝。

標頭檔案kernel.h中提供了如下的記憶體池 api:

zephyr筆記 2 3 3 堆記憶體池

堆記憶體池是乙個預定義的記憶體池物件,它允許執行緒以類似 malloc 方式從公共記憶體區域動態分配記憶體。我正在學習 zephyr,乙個很可能會用到很多物聯網裝置上的作業系統,如果你也感興趣,可點此檢視帖子zephyr學習筆記彙總。只能定義乙個堆記憶體池。與其他記憶體池不同,堆記憶體池不能使用其記...

DBCP連線池使用方法

使用 如下 test public void f1 throws sqlexception else 表結構什麼的就不說了,主要是得到datasource就好了,不過dbcp用的是basicdatasource 而已 下面講講怎麼通過配置檔案的方式 如何配置檔案 連線基本設定 driverclass...

共享記憶體的使用方法

使用共享記憶體的一般步驟 1 獲取共享記憶體的id 2 將共享記憶體對映到本程序虛擬記憶體空間的某個區域 3 不再使用時,接觸對映 4 不需要時,刪除它。注意 建立的共享記憶體是物理記憶體,必須要對映到本程序的記憶體空間才能使用。ipc stat獲得的屬性資訊查詢課本或其他資料 演示 p1傳送資訊給...