linux C Obstack

来源:http://www.cnblogs.com/san-fu-su/archive/2016/08/05/5739780.html
-Advertisement-
Play Games

Obstack介紹 Obstack初始化 在Obstack中申請對象 釋放對象 申請growing object 獲取Obstack狀態 數據對齊 以下是來自wiki對obstack的介紹: Obstack是C標準庫裡面對記憶體管理的GNU擴展(實際上就是GNU C library了)。Obstack ...


 

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


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

-Advertisement-
Play Games
更多相關文章
  • ASPX 優點: 通過上面小小的對比,不難看出,與ASP.NET MVC緊密集成,對於以往ASP.NET開發人員有更好體驗。其實它還有其他幾優點: ●智能感應 ●能選擇其它語言的 CodeDom provider (例如: C#, VB.NET, F#, Boo, Nemerle) ●立即編譯或預編 ...
  • ...
  • 物理文件是我們最常用到的原始配置的載體,最佳的配置文件格式主要由三種,它們分別是JSON、XML和INI,對應的配置源類型分別是JsonConfigurationSource、XmlConfigurationSource和IniConfigurationSource。 ...
  • 為什麼不直接使用<img src="{{phone.imageUrl}}">因為瀏覽器會請求{{phone.imageUrl}}這個url。 ...
  • 1、基本思想:設無向連通網為G=(V, E),令G的最小生成樹為T=(U, TE),其初態為U=V,TE={ },然後,按照邊的權值由小到大的順序,考察G的邊集E中的各條邊。若被考察的邊的兩個頂點屬於T的兩個不同的連通分量,則將此邊作為最小生成樹的邊加入到T中,同時把兩個連通分量連接為一個連通分量; ...
  • 所謂最小乘積生成樹,即對於一個無向連通圖的每一條邊均有兩個權值xi,yi,在圖中找一顆生成樹,使得Σxi*Σyi取最小值。 直接處理問題較為棘手,但每條邊的權值可以描述為一個二元組(xi,yi),這也就不難想到將生成樹轉化為平面內的點,x代表Σxi,y代表Σyi(註意這裡的xi,yi指的是在生成樹中 ...
  • 原文:http://www.cnblogs.com/san-fu-su/p/5737984.html C裡面沒有垃圾回收機制,有時候你申請了動態記憶體卻忘記釋放,這就尷尬了(你的程式扮演了強盜角色,有借有還才是好孩子)。當你想找出記憶體泄露的地方時,有的投入海量的代碼中,頭痛不已。還好GNU C庫提供了 ...
  • 最近在做統計錢的計算時遇到的一個需求,需要將一個大類別下的每一種錢進行特定的運算然後獲得六年的錢,最後將這些錢按照年份進行彙總,獲得總得大類型的六年的錢,在這個過程中採用了這種方法,每次算得錢放在map中,然後將map進行合併,寫篇隨筆mark下。 public class CombineMap { ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...