首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Linux C Obstack:基於區域的高效內存池管理機制詳解

     編輯:關於C語言

什麼是 Obstack?

Obstack = Object Stack。GNU C 庫擴展,屬於Region-based memory management(基於區域的內存管理)。將相關對象集中在一個邏輯棧中,支持:

  • 任意數量、任意大小對象分配。
  • 後進先出順序釋放(棧規則)。
  • 一次性銷毀整個 Obstack,無需逐個 free。
  • 避免 malloc/free 碎片化,提高局部性。

本質:內存池管理員。預先分配大塊 chunk(默認 4KB),在池中按棧式分配對象;池滿自動申請新 chunk。對象間可能需填充對齊(以空間換時間)。

核心結構與初始化

#include <obstack.h>
struct obstack;  // 不透明結構,僅記錄狀態與 chunk 鏈表指針

// 必須由用戶定義的宏(指向分配/釋放函數)
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

// 可選:分配失敗處理器
void (*obstack_alloc_failed_handler)(void);

// 初始化
int obstack_init(struct obstack *ptr);  // 總返回 1,失敗調用 handler

// 示例
static struct obstack myobstack;
obstack_init(&myobstack);
// 或動態
struct obstack *p = malloc(sizeof(struct obstack));
obstack_init(p);

Chunk 大小控制

// 宏展開為左值,可直接賦值
if (obstack_chunk_size(ptr) < NEW_SIZE) obstack_chunk_size(ptr) = NEW_SIZE;

增大 chunk 減少系統調用,提高效率;減小無益處。

對象分配與釋放

固定大小對象

void *obstack_alloc(struct obstack *ptr, int size);          // 不初始化
void *obstack_copy(struct obstack *ptr, void *addr, int size); // 從 addr 複製 size 字節初始化
void *obstack_copy0(struct obstack *ptr, void *addr, int size); // 複製並追加 \0,適合字符串

釋放:

void obstack_free(struct obstack *ptr, void *obj);
  • obj == NULL:釋放所有對象,保留 Obstack 結構(chunk 歸還)。
  • obj != NULL:釋放 obj 及其之後分配的所有對象(棧頂回縮)。
  • 保留首對象地址可實現「清空但保留 Obstack」:obstack_free(ptr, first_obj)。

增長型對象:逐步構建大對象

利用 chunk 連續空間特性,支持增量構建(如動態字符串、可變長數組)。

void obstack_blank(struct obstack *ptr, int size);           // 預留未初始化空間
void obstack_grow(struct obstack *ptr, void *data, int size); // 追加數據
void obstack_grow0(struct obstack *ptr, void *data, int size); // 追加並加 \0
void obstack_1grow(struct obstack *ptr, char c);             // 追加單字符
void obstack_ptr_grow(struct obstack *ptr, void *data);      // 追加指針
void obstack_int_grow(struct obstack *ptr, int data);        // 追加 int

關鍵:構建完成必須調用 void *obstack_finish(struct obstack *ptr) 獲取最終地址並固化對象。
obstack_object_size(ptr) 返回當前構建大小(僅 finish 前有效)。
取消構建:obstack_free(ptr, obstack_finish(ptr))。

快速模式(省去空間檢查)

在確信 chunk 剩餘空間足夠時,使用 _fast 後綴版本(如 obstack_1grow_fast),跳過邊界檢查,極致性能。

輔助:int obstack_room(struct obstack *ptr) 返回當前 chunk 可安全寫入字節數。

狀態查詢

void *obstack_base(struct obstack *ptr);        // 當前構建對象起始地址(假定,可能換 chunk)
void *obstack_next_free(struct obstack *ptr);   // 當前 chunk 首個空閒字節地址
int obstack_object_size(struct obstack *ptr);   // 等價於 next_free - base

內存對齊控制

int obstack_alignment_mask(struct obstack *ptr); // 掩碼,值為 2^n-1,地址對齊到 2^n
// 修改後下次分配生效;growing object 立即生效(finish 後可見)

總結

  • Obstack 適合「階段性分配、批量釋放」場景:編譯器符號表、解析器 AST、請求上下文內存等。
  • 所有操作均為宏實現,極高效;調試時可改用函數版本(參考 GNU 手冊)。
  • 核心約束:釋放順序必須符合棧規則(LIFO),違規行為未定義。

文檔來源:原文鏈接

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved