程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> linux C Obstack,linuxobstack

linux C Obstack,linuxobstack

編輯:關於C語言

linux C Obstack,linuxobstack


 

Obstack介紹

Obstack初始化

在Obstack中申請對象

釋放對象

申請growing object

獲取Obstack狀態

數據對齊

以下是來自wiki對obstack的介紹:

  Obstack是C標准庫裡面對內存管理的GNU擴展(實際上就是GNU C library了)。Obstack===Object stack。沒錯,Obstack就是一個棧,棧裡面的元素是對象object(不是面向對象的對象哦,這裡的對象單指數據元素)。這些數據是動態的,也就是使用的是動態內存。這種內存管理技術屬於Region-based memory management。

  那什麼叫基於區域的內存管理呢?區域指的是我們申請的數據對象存放的位置。在這種內存管理模式下,我們將所有申請的數據對象集中放在一起(當然咯,地址不一定連續。集中在一起是一種邏輯結構,比如Obstack的棧)。好處就是,可以一次性的釋放內存,集中管理。這下你對Obstack有了大體上的了解了吧。

以下為GNU C的Obstack描述:

  Obstack是一種內存池,內存池裡面包含了數據對象棧。

  啥叫內存池呢?內存池也叫做固定大小的塊內存申請(fixed-size blocks allocation),同樣也是一種內存管理技術。這種技術允許動態申請內存。(是不是迷糊了?前面還說固定,現在又說動態了。實際上固定的是總大小,動態是指內存實際申請使用。如果你用過virtual box,沒錯就是那個百分之60剛玩linux的人都會安裝的東西。裡面創建虛擬硬盤時對動態分配有這樣的描述:虛擬磁盤只是逐漸占用物理硬盤空間[直至達到分配的大小],不過當其內部空間不用時不會自動縮減暫用的物理硬盤空間])這種方式有點類似malloc或者C++的new操作。但是malloc和new操作都會造成內存碎片化問題(別打我,這是wiki講的,不關我的事)。更有效地方式就是使用相同大小內存池了。預先申請,集中管理。應用程序在內存池裡面自由的玩耍,從來不上岸-_-|||。

  回過頭繼續講Obstack。你可以創建任意數量的獨立的Obstack,然後在這些Obstack裡面申請對象。這些對象遵循棧的邏輯結構:最後申請的對象必須第一個釋放。不同的Obstack裡面的數據是相互獨立的,沒有任何關系。除了對內存釋放順序的要求之外,obstack是非常通用的:一個Obstack可以包含任意數量任意尺寸的對象。

  Obstack裡面內存申請的實現用的一般都是宏,很有效率吧。如果你不想使用宏(理由是:方便調試),可以看一看我的另一篇文章。這篇文章的最後介紹了如何避免使用預定義的宏。唯一的內存空間損耗就是不同對象之間可能需要內存填充,讓每一個對象都起始於合適的邊界線,這一點實際上是用空間換取時間。

  Obstack的表現形式是一個結構體:struct obstack。這個結構有一個非常小的固定大小,記錄了obstack的狀態,以及如何找到該Obstack裡的對象。但是呢,obstack結構體自身不包含任何對象,別妄想直接探尋struct obstack的內容了。必須使用規定的函數才行,這點沒得商量。

  你可以通過聲明一個struct obstack類型的變量來創建obstack。或者動態申請struct obstack *obstack = (struct obstack *)malloc(sizeof(struct obstack)); 你還可以obstack裡面使用obstack(然並卵,GNU C library文檔自己說的)

  Obstack使用的函數都需要指定使用的是那個obstack。Obstack裡面的對象會被打包成一個大的內存塊(叫做chunks)。struct obstack結構指針指向當前使用的chunks。

  每當你申請的對象無法塞進之前的chunk時,都會創建一個新的chunk。這些chunk以何種形式連接在一起(鏈表?樹?),不是我們關心的啦。這些交由obstack自動管理。chunk由obstack自動創建,但創建的方式得由你來決定,一般會直接或間接的用到malloc函數。

  聯想我們之前講到的內存池:chunk是固定大小的池。Obstack只是一種池的管理員:他告訴來洗澡的人必須遵守規定,最後來的必須先走。

 

Obstack初始化:

#include<obstack.h>
int obstack_init(struct obstack *obstack-ptr)

 

 

  obstack_init實際上是一個宏實現。obstack_init會自動調用obstack_chunk_alloc函數來申請chunk,注意這還是個宏,需要你指定這個宏指向的函數。如果內存申請失敗了會調用obstack_alloc_failed_handler指向的函數,沒錯依舊是宏。如果chunk裡面的對象都被釋放了,obstack_chunk_free指向的函數被用來返回chunk占用的空間。目前版本的obstack_init永遠只返回1(之前的版本會在失敗的時候返回0)

實例:

#include<obstack.h>
#include<stdlib.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

//靜態申請obstack
static struct obstack myobstack;
obstack_init(&myobstack);

//動態申請obstack
struct obstack *myobstack_ptr = (struct obstack*) malloc (sizeof (struct obstack))
obstack_init(myobstack_ptr)

    obstack chunk的大小默認情況下為4096。如果你想自定義chunk的大小,需要使用宏obstack_chunk_size

int obstack_chunk_size (struct obstack* obstack-ptr)

   注意這實際上是個左值(C++裡面有麻煩的左值引用,右值引用 囧rz)。obstack-ptr如之前的myobstack所示,指明了是哪個obstack。如果你適當的提高chunk的大小,有利於提高效率。減小則沒啥好處。。。

if (obstack_chunk_size (myobstack_ptr) < new-chunk-size)
    obstack_chunk_size (myobstack_ptr) = new-chunk-size

 

在Obstack裡面申請對象:

   最直接的方法使用aobstack_alloc函數

void * obstack_alloc (struct obstack *obstack-ptr, int size)

 

  調用方式和malloc差不多, 對新申請的空間不初始化。如果chunk被object填滿了,obstack_alloc會自動調用obstack_chunk_alloc。

struct obstack string_obstack;
/*
....
初始化內容
....
*/
char * copystring (char *string)
{
    size_t len = strlen (string) + 1;
    char *s = (char*) obstack_alloc (&string_obstack, len);
    memcpy (s, string , len);
    return s;
}

 

  如果想在申請時初始化,需要用到obstack_copy或者obstack_copy0

void * obstack_copy (struct obstack *obstack-ptr, void *address, int size)
//使用從地址address開始復制size大小的數據初始化,新申請的object內存大小也為size

void *obstack_copy0 (struct obstack *obstack-ptr, void *address, int size)
//同obstack_copy但結尾處額外添加一個空字符,在復制以NULL結尾的字符串時很方便。

 

 

  釋放Obstack裡面的對象:

  同樣很簡單,我們使用函數obstack_free

void obstack_free  (struct obstack *obstack-ptr, void *object)

 

  如果object是空指針的話,所有的對象都被釋放,留下一個未初始化的obstack,然後obstack庫會自動釋放chunk。如果你指定了object地址,那自這個object之後的所有對象都被釋放。值得注意的是:如果你想釋放所有object但同時保持obstack有效,可以指定第一個object的地址

obstack_free (obstack_ptr, first_object_allocated_ptr);

 

  

可增長內存空間的對象:

  由於obstack chunk的內存空間是連續的,在其中的對象空間可以一步步搭建一直增加到結尾。這種技術稱之為growing object。盡管obstack可以使用growing object,但是你無法為已申請好的對象使用這項技術(理由是如果這對象之後還有對象,會造成沖突)

void obstack_blank (struct obstack *obstack-ptr, int size)
//添加一個為初始化的growing object

void obstack_grow (struct obstack *obstack-ptr, void *data, int size)
//添加一個初始化的空間,類似與obstack_copy

void obstack_grow0 (struct obstack *obstack-ptr, void *data, int size)
//obstack_grow類似與obstack_copy, 那obstack_grow0你說類似與誰?

void  obstack_lgrow (struct obstack *obstack-ptr, charc)
//一次添加一個字符(字節)

void    obstack_ptr_grow (struct obstack *obstack-ptr, void *data)
//一次添加一個指針。。。大小為(sizeof(void *)

void obstack_int_grow (struct obstack *obstack-ptr, int data)
//一次添加一個int型數據,大小為sizeof(int)

 

  在growing object中最重要的函數是obstack_finish, 因為只有調用了本函數之後才會返回growing object 的最終地址。

void *obstack_finish (struct obstrack *obstrack-ptr)

 

  如果你想獲取growing object當前大小,可以使用obstack_object_size

int obstack_object_size (struct obstack *obstrack-ptr)
//只能用在obstack_finish之前,否則只會返回0

 

  如果你想取消一個正在增長的對象,必須先結束他,然後再釋放。示例如下:

obstack_free (obstack_ptr, obstack_finish (obstack_ptr))

 

  上面的函數在添加數據時會檢查是否由足夠的空間。如果你只增加一丁點的空間,檢查這一步驟顯然是多余的。我們可以省略這一步驟,更快的growing。這裡關於growing object額外在介紹一個函數:

int obstack_room (struct obstack *obstack-ptr)
//返回可以安全添加的字節數

 

  其余的快速添加函數只需要在之前的growing object函數添加後綴_fast即可(如果不清楚可以查看GNU C 關於這部分的介紹)

 

Obstack 的狀態:

以下函數用於獲取obstack的狀態:

void * obstack_base (struct obstack *obstack-ptr)
//返回正在增長的對象的假定起始地址。為啥是假定呢,因為如果你增長的過大,當前chunk的空間不夠,obstack就會新創建一個chunk,這樣地址就變了。


void *obstack_next_free (struct obstack *obstack-ptr)
//返回當前chunk未被占用的第一個字節的地址

int obstack_object_size (struct obstack *obstack-ptr)
//返回當前growing object的大小。等同與:
//obstack_next_free (obstack-ptr) -obstack_base (obstack-ptr)

 

 

Obstack 裡的數據對齊問題

int obstack_alignment_mask (struct obstack *obstack-ptr)

 

  宏展開後是一個左值。如果是函數實現,返回的是掩碼。你給他復制也應該是掩碼。掩碼的值應該是2的n次方減一,換算後也就是說地址必須是2的n次方的倍數。如果你改變了掩碼,只有下次申請object的時候才會生效(特例是growing object:立即生效,調用obstack_finish後就能看到效果了)

 本文地址http://www.cnblogs.com/san-fu-su/p/5739780.html

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved