C C 中記憶體分配與STL中的空間配置

2021-08-21 17:00:50 字數 4426 閱讀 8378

stl空間配置器

最近在看侯捷的《stl原始碼解析》,按照裡面的思路寫了乙個迷你的stl,由於stl中的記憶體分配和空間配置較為複雜,在這裡總結一下。

c語言中主要有三個函式進行記憶體分配,分別是malloc,realloc,calloc,釋放記憶體的函式是free,標頭檔案是

1.malloc

函式原型:void *malloc(unsigned int num_bytes);。分配的是以位元組計算的結果,返回的指標型別是void*

注意:不會進行初始化操作,需要手動計算分配的空間大小,同時需要對返回的型別進行強制轉化。

使用:

int * a = (int*)malloc(sizeof(int) * 10);

for (int i = 0; i < 10; ++i)

*(a + i) = i;

for (int i = 0; i < 10; ++i)

cout

<< *(a + i) << " ";

// 0 1 2 3 4 5 6 7 8 9

2.realloc

對原來的位址進行重新分配。如果分配的空間小於原來的空間,還是會在原來的位址上。如果分配的空間大於原來的空間,如果原位址後面空間足夠,則繼續分配;否則會先釋放原來的空間,然後分配新的位址。

函式原型:void *realloc(void *mem_address, unsigned int newsize);

使用:

int *b = (int*)realloc(a, sizeof(int) * 5);

cout

<< (int)b << " "

<< (int)a << endl; // 位址一定相同

int *b = (int*)realloc(a, sizeof(int) * 50);

cout

<< (int)b << " "

<< (int)a << endl; // 位址可能相同

3.calloc

函式原型:void *calloc(size_t n, size_t size);

兩個引數分別是分配的元素個數和單個元素的大小。calloc的最大特點是會將分配的記憶體初始化為0

使用:

int *c =(int*)calloc(10, sizeof(int));

for (int i = 0; i < 10; ++i)

cout

<< *(c + i) << " ";

// 0 0 0 0 0 0 0 0 0 0

4.free

函式原型:void free(void *ptr)

釋放空間,但需要手動把指標置空,因為只是釋放並沒有改變指標的指向,只是這一塊記憶體已經不屬於這個指標。

c++ 中使用new/delete來代替c語言中的相關庫函式。主要區別如下:

1.new/delete是操作符不是庫函式

2.new會自動計算空間大小

3.new除了分配空間,還會自動呼叫物件的建構函式,對申請的空間進行構造

4.delete會先呼叫析構函式,然後釋放空間

正常情況下new/delete都是完成空間申請,物件構造,物件析構,空間釋放功能,但也有幾個不同的函式原型,提供不同的功能。

1.plain new

這個就是正常的new,在分配失敗的情況下,丟擲異常std::bad_alloc而不是返回null

void* operator new(std::size_t) throw(std::bad_alloc);

void operator delete(void *) throw();

2.nothrow new

這是不丟擲異常的new形式,如果分配失敗,返回null

void * operator new(std::size_t,const std::nothrow_t&) throw();

void operator delete(void*) throw();

3.placement new

在一塊已經分配空間的記憶體上構造物件,不分配新的空間,不會丟擲異常。

void* operator new(size_t,void*);

void operator delete(void*,void*)

allocate分配空間

construct構造

destroy析構

deallocate釋放記憶體

memory的函式將new/delete的功能拆成四個部分,分別是申請空間,構建,析構,釋放。

具體使用:

allocator alloc;

// 分配

auto begin = alloc.allocate(10);

auto p = begin;

// 構造

for (int i = 0; i < 10; ++i)

alloc.construct(p++, i);

for (int i = 0; i < 10; ++i)

printf("%d ", *(begin + i));

printf("\n");

// 析構

p = begin;

for (int i = 0; i < 10; ++i)

alloc.destroy(p++);

// 釋放記憶體

alloc.deallocate(begin, 10);

在stl的設計中,使用的是多層的空間配置器,因為頻繁的申請釋放空間將會造成記憶體的碎片化。在這裡使用兩層的空間配置器。

一級空間配置器分配的是大於128位元組的空間

如果分配不成功,呼叫控制代碼釋放一部分記憶體

如果還不能分配成功,丟擲異常

維護乙個鍊錶,鍊錶每個節點是8的倍數大小,每乙個子鍊錶擁有相同大小的節點。

當使用者申請的空間小於128位元組時,將位元組數擴充套件到8的倍數,然後在自由鍊錶中查詢對應大小的子鍊錶

如果在自由鍊錶查詢不到或者塊數不夠,則向記憶體池進行申請,一般一次申請20塊

如果記憶體池空間足夠,則取出記憶體

如果不夠分配20塊,則分配最多的塊數給自由鍊錶,並且更新每次申請的塊數

如果一塊都無法提供,則把剩餘的記憶體掛到自由鍊錶,然後向系統heap申請空間,如果申請失敗,則看看自由鍊錶還有沒有可用的塊,如果也沒有,則最後呼叫一級空間配置器

在stl的實現中,封裝原始的alloc,原始的alloc只分配固定原始的空間,並不會構建和析構物件。封裝後的******allocate能夠分配空間,構建物件,析構物件,釋放空間。構建物件使用palcement new,析構物件顯式呼叫析構函式。

具體實現:

template

class ******allocate

static

void deallocate(value_ptr p, size_type n)

static

void construct(value_ptr p, const value_type &value)

static

void destroy(value_ptr p)

};template

allocator******allocate::alloc = allocator();

目前的stl實現空間配置,setvectorstack等容器

完整**見github

如有錯誤,歡迎指正~

C C 分配記憶體空間

方法 c malloc calloc realloc free c new delete 函式原型 請求成功返回空間首位址,失敗返回 null include void malloc size t size 分配size位元組的連續記憶體,不負責初始化,使用memset初始化。void calloc...

STL中的記憶體分配方式

在stl中考慮到小型區塊所可能造成的記憶體碎片問題,sgi stl設計了雙層級配置器,第一級配置器直接使用malloc 和free 第二級配置器則視情況採用不同的策略 當配置區塊超過128bytes 時,則視之為足夠大,便呼叫第一級配置器 當配置區塊小於128bytes時,則視之為過小,為了降低額外...

C C 中的記憶體分配機制

本文是總和了其它的幾篇帖子,主要是 一 字串 乙個字元乙個位元組,加上最後的乙個結束符 0 其中,strlen函式返回的字串長度不包括 0 sizeof操作符返回的位元組長度是包括 0 的。二 結構體的儲存 typedef struct sample sizeof sample 為1個位元組 typ...