BGET內存分配器

BGET內存分配器


BGET是一個全面的內存分配包,能夠根據應用程序的須要輕鬆配置。BGET在分配和釋放緩衝區所需的時間以及緩衝池管理所需的內存開銷方面都頗有效。它會自動整合連續的空間,以最大限度地減小碎片。BGET由編譯時定義配置,主要選項包括:html

  • 內置的測試程序,用於練習BGET並演示如何使用各類功能。
  • 經過「第一次適合」或「最佳適合」方法進行分配。
  • 在發佈時擦除緩衝區以捕獲引用先前釋放的存儲的代碼。
  • 用於轉儲單個緩衝區或整個緩衝池的內置例程。
  • 檢索分配和池大小統計信息。
  • 將緩衝區大小量化爲2的冪以知足硬件對齊約束。
  • 經過對用戶定義函數的回調自動池壓縮,增加和收縮。

BGET的應用範圍能夠從基於ROM的嵌入式程序中的存儲管理到提供構建包含垃圾收集的多任務系統的框架。BGET使用該<assert.h>機制進行普遍的內部一致性檢查 ; 全部這些檢查均可以經過使用已NDEBUG定義的編譯來關閉,從而產生具備最小尺寸和最大速度的BGET版本。算法

BGET的基本算法經受住了時間的考驗; 自第一次實施此代碼以來已超過25年。然而,它比許多操做系統的原生分配方案效率要高得多:Macintosh和Microsoft Windows,其中兩個程序經過將BGET分層做爲底層系統頂層的應用程序級內存管理器而得到了大幅提高。安全

BGET已在最大的主機 和最低的微處理器上實現。它已成爲多任務操做系統,多線程應用程序,數據網絡交換處理器中的嵌入式軟件以及大量C程序的核心。雖然它多年來已經增長了靈活性和附加選項,但它仍然快速,高效,便攜,而且易於集成到您的程序中。網絡

BGET實施假設

BGET以儘量便攜的方言編寫。關於底層硬件架構的惟一基本假設是分配的存儲器是線性陣列,其能夠做爲C的向量來尋址char對象。在分段地址空間體系結構上,這一般意味着BGET應該用於在單個段內分配存儲(儘管一些編譯器模擬分段體系結構上的線性地址空間)。在分段體系結構上,BGET緩衝池可能不會大於一個段,但因爲BGET容許任意數量的單獨緩衝池,所以對可管理的總存儲沒有限制,只能在最大的單個對象上進行管理。分配。具備線性地址架構的機器,例如VAX,680x0,SPARC,MIPS或本機模式下的Intel 80386及更高版本,能夠無限制地使用BGET。多線程

BGET入門

儘管BGET能夠採用多種方式進行配置,但使用BGET有三種基本方法。下面介紹的功能將在下一節中介紹。請原諒爲了提供路線圖而提出的前瞻性參考資料,以指導您可能須要的BGET功能。架構

嵌入式應用

嵌入式應用程序一般具備專用於緩衝區分配的固定存儲區域(一般位於與包含可執行代碼的ROM不一樣的單獨RAM地址空間中)。要在這樣的環境中使用BGET,只需bpool()使用RAM中的緩衝池區域的起始地址和長度進行調用,而後分配緩衝區bget()並將其釋放 brel()。內存很是有限但CPU速度充足的嵌入式應用程序能夠經過配置BGET進行 BestFit分配(在其餘環境中一般不值得)。框架

malloc() 仿真

若是C庫malloc()函數太慢,在開發環境中不存在(例如,本機Windows或Macintosh程序),或者不適合,則能夠將其替換爲BGET。最初bpool()經過調用操做系統的低級內存分配器來定義一個適當大小的緩衝池。而後使用bget()bgetz()和 分配緩衝區bgetr()(最後兩個容許將初始化的緩衝區分配爲零,而且[低效]從新分配現有緩衝區以與C庫函數兼容)。經過調用釋放緩衝區brel()。若是緩衝區分配請求失敗,請從底層操做系統獲取更多存儲,經過另外一次調用將其添加到緩衝池bpool(),而後繼續執行。函數

自動存儲管理

您能夠將BGET用做應用程序的本機內存管理器,並經過使用BECtl定義的變量編譯BGET ,而後調用 bectl()和提供存儲壓縮,獲取和釋放的功能,實現自動存儲池擴展,收縮和可選的特定於應用程序的內存壓縮做爲標準池擴展增量。全部這些功能都是可選的(儘管提供沒有采集功能的釋放功能沒有多大意義,是嗎?)。一旦定義了回調函數bectl(),您就能夠像之前同樣使用bget()和 brel()分配和釋放存儲。您能夠提供初始緩衝池,bpool()或者依靠自動分配來獲取整個池。打電話時 bget()不能知足,BGET首先檢查是否提供了壓縮功能。若是是這樣,則調用它(具備知足分配請求所需的空間和序列號,以容許連續調用壓縮例程而不循環)。若是壓縮函數可以釋聽任何存儲(它不須要知道它釋放的存儲是否足夠),它應該返回非零值,所以BGET將重試分配請求,若是再次失敗,則再次調用壓縮函數具備次高的序列號。測試

若是壓縮函數返回零,指示沒法釋放空間,或者沒有定義壓縮函數,則BGET接下來測試是否提供了非NULL分配函數 bectl()。若是是,則使用參數調用該函數,該參數指示須要多少字節的額外空間。這將是調用中提供的標準池擴展增量, bectl()除非原始bget()調用請求大於此的緩衝區; 大於標準池塊的緩衝區能夠在此模式下由BGET「書籍」管理。若是分配函數成功得到存儲,則返回指向新塊的指針,BGET擴展緩衝池; 若是失敗,則分配請求失敗並向調用者返回NULL。若是是非NULL 提供了釋放功能,經過將其地址傳遞給釋放功能,將變爲徹底空的擴展塊釋放到全局空閒池。ui

BGET具備適當的分配,釋放和壓縮功能,可用做很是複雜的內存管理策略的一部分,包括垃圾收集。(但請注意,BGET自己並非垃圾收集器,開發這樣的系統須要更多的邏輯和仔細設計應用程序的內存分配策略。)

BGET功能描述

BGET實現的功能(某些功能由如下某些可選設置啓用):

void bpool(void *緩衝, bufsize LEN);

使用從緩衝區開始的存儲 建立len個字節的緩衝池。您能夠隨後調用以向整個緩衝池貢獻額外的存儲空間。 bpool()

void *bget(bufsize 尺寸);

分配大小字節的緩衝區。返回緩衝區的地址,或者NULL若是沒有足夠的內存可用於分配緩衝區。

void *bgetz(bufsize 尺寸);

分配大小字節的緩衝區並將其清除爲全零。返回緩衝區的地址,或者NULL若是沒有足夠的內存可用於分配緩衝區。

void *bgetr(void *緩衝區, bufsize 新聞);

從新分配先前分配的緩衝區bget(),將其大小更改成新聞化並保留全部現有數據。 NULL若是沒有足夠的內存可用於從新分配緩衝區,則返回,在這種狀況下,原始緩衝區保持不變。

void brel(void *BUF);

將以前分配 的緩衝區buf返回bget()到空閒空間池。

void bectl(int (*compact )(bufsize sizereq , int 序列), void *(*獲取)(bufsize 大小), void (*釋放)(void *buf ), bufsize pool_incr);

擴展控制:指定在分配請求失敗時包能夠經過其壓縮存儲(或採起其餘適當的操做)的功能,而且可選地在必要時自動獲取擴展塊的存儲,並在它們變空時釋放這些塊。若是compact是非NULL,則只要緩衝區分配請求失敗,就會調用compact函數,其參數指定知足分配請求所需的字節數(總緩衝區大小,包括頭開銷),以及指示數量的序列號。緊湊的連續調用嘗試知足此分配請求。對於Compact上的第一次調用,序列號爲1 對於給定的分配請求,以及後續呼叫的增量,容許緊湊功能採起愈來愈可怕的措施以試圖釋放存儲。若是 compact函數返回非零值,則從新嘗試分配嘗試。若是compact返回0(若是它沒法釋聽任何空間或向緩衝池添加存儲,則必須返回),分配請求將失敗,若是獲取參數爲非,則能夠觸發自動池擴展NULL。在調用compact函數時,緩衝區分配器的狀態與分配請求時的狀態相同; 所以,緊湊的功能能夠調用 brel()bpool()bstats()和/或以任何有效的方式直接操做緩衝池是控制中的應用程序。可是,這並無減輕緊湊功能的須要,以確保它所採起的任何操做都不會改變發出分配請求的應用程序下面的內容。例如,在從新分配過程當中釋放緩衝區的 緊湊功能bgetr()會致使災難。實現安全有效的緊湊機制須要仔細設計應用程序的內存架構,而且一般不能輕易地改裝到現有代碼中。

若是acquire爲non NULL,則只要分配請求失敗,就會調用該函數。若是獲取 功能成功分配請求的空間並返回指向新區域的指針,則將使用擴展緩衝池繼續分配。若是獲取沒法獲取請求的空間,則應返回NULL而且整個分配過程將失敗。 pool_incr指定正常的擴展塊大小。提供獲取功能將致使後續 bget()請求緩衝區太大而沒法在連接塊方案中管理(換句話說,大於 pool_incr減去緩衝區開銷)直接經過調用來知足得到功能。僅當系統中的全部池塊都是pool_incr給定的大小時,纔會自動釋放空池塊。

void bstats(bufsize *curalloc , bufsize *totfree , bufsize *maxfree , long *nget , long *nrel);

當前分配的空間量存儲在curalloc指向的變量中。總可用空間(池中全部空閒塊的總和)存儲在totfree指向的變量中 ,而且空閒空間池中最大單個塊的大小存儲在maxfree指向的變量中。ngetnrel指向的變量分別用成功(非NULL返回)bget()調用的數量和brel()調用的數量填充。

void bstatse(bufsize *pool_incr , long *npool , long *npget , long *nprel , long *ndget , long *ndrel);

擴展統計信息:擴展塊大小將存儲在pool_incr指向的變量中,若是禁用自動擴展塊釋放,則爲負數。當前活動池塊的數量將存儲到npool指向的變量中。npget和 nprel指向的變量將分別填充已發生的擴展塊獲取和釋放的數量。ndgetndrel指向的變量將 分別由經過獲取和釋放函數直接分配的塊管理的數量bget()brel()調用填充。

void bufdump(void *BUF);

緩衝區指向BUF是在標準輸出傾倒。

void bpoold(void *pool , int dumpalloc , int dumpfree);

緩衝池池中的全部緩衝區(先前由bpool()上的調用初始化按升序內存地址順序列出。若是dumpalloc非零,則轉儲已分配緩衝區的內容; 若是dumpfree非零,則轉儲空閒塊的內容。

int bpoolv(void *);

先前經過調用初始化的命名緩衝池將 bpool()針對錯誤指針,覆蓋數據等進行驗證。若是NDEBUG未定義編譯,則任何錯誤都會生成斷言失敗。不然,若是池有效則返回1,若是找到錯誤則返回0。

BGET配置

如下定義的變量bget.c容許您配置BGET的各類功能和操做模式。

#define TestProg 20000 / *生成內置測試程序
                              若是定義。值指定
                              緩衝區分配嘗試次數
                              測試程序應該作。* /

#define SizeQuant 4 / *緩衝區分配大小量程:
                              分配的全部緩衝區都是
                              這個大小的倍數。這個
                              必須是兩我的的力量。* /

#define BufDump 1 / *定義此符號以啓用
                              轉儲的bpoold()函數
                              緩衝池中的緩衝區。* /

#define BufValid 1 / *定義此符號以啓用
                              bpoolv()函數用於驗證
                              一個緩衝池。* /

#define DumpData 1 / *定義此符號以啓用
                              容許的bufdump()函數
                              轉儲已分配的內容
                              或免費緩衝。* /

#define BufStats 1 / *定義此符號以啓用
                              計算的bstats()函數
                              緩衝區中的總可用空間
                              游泳池,最大的可用
                              緩衝區和總空間
                              目前已分配。* /

#define FreeWipe 1 / *擦除保證的免費緩衝區
                              絆倒的垃圾模式
                              試圖使用的不法分子
                              指向已釋放緩衝區的指針。* /

#define BestFit 1 / *什麼時候使用最佳擬合算法
                              尋找空間
                              分配請求。這用
                              記憶更有效率,可是
                              分配會慢得多。* /

#define BECtl 1 / *定義此符號以啓用
                              bectl()函數用於自動
                              泳池空間控制。* /
相關文章
相關標籤/搜索