primitive-memory
# 前言
提示
从平地到万丈高楼,万丈高楼平地起 锱铢必较
C++应用程序使用memory的途径
C++ application
| | | |
| | | c++ Library(std::allocator)
| | | |
| | c++ primitives(new,new[],::operator new(),...)
| | |
| CRT(malloc/free)
| |
O.S.API(such as HeapAlloc,VisualAlloc,...)
# primitives基础工具
void test_primitives()
{
cout << "\ntest_primitives().......... \n";
void* p1 = malloc(512); //512 bytes
free(p1);
complex<int>* p2 = new complex<int>; //one object
delete p2;
void* p3 = ::operator new(512); //512 bytes
::operator delete(p3);
//以下使用 C++ 標準庫提供的 allocators。
//其接口雖有標準規格,但實現廠商並未完全遵守;下面三者形式略異。
#ifdef _MSC_VER
//以下兩函數都是 non-static,定要通過 object 調用。以下分配 3 個 ints.
int* p4 = allocator<int>().allocate(3, (int*)0);
allocator<int>().deallocate(p4,3);
#endif
#ifdef __BORLANDC__
//以下兩函數都是 non-static,定要通過 object 調用。以下分配 5 個 ints.
int* p4 = allocator<int>().allocate(5);
allocator<int>().deallocate(p4,5);
#endif
#ifdef __GNUC__
//以下兩函數都是 static,可通過全名調用之。以下分配 512 bytes. 已不再使用
//void* p4 = alloc::allocate(512);
//alloc::deallocate(p4,512);
//以下兩函數都是 non-static,定要通過 object 調用。以下分配 7 個 ints.
void* p4 = allocator<int>().allocate(7);
allocator<int>().deallocate((int*)p4,7);
//以下兩函數都是 non-static,定要通過 object 調用。以下分配 9 個 ints.
void* p5 = __gnu_cxx::__pool_alloc<int>().allocate(9);
__gnu_cxx::__pool_alloc<int>().deallocate((int*)p5,9);
#endif
}
# new, delete expression
# new expression
先分配内存,然后调用构造函数
Complex* pc = new Complex(1, 2);
//||编译器转为
Complex* pc;
try{
void* mem = operator new(sizeof(Complex));//里面调用的是malloc/_callnewh
pc = static_cast<Complex*>(mem);
pc->Complex::Complex(1, 2);
//注意:只有编译器才可以像上面那样调用Ctor
}
catch(std::bad_alloc){
//...
}
# delete expression
先调用析构函数,然后释放内存
delete pc;
//||编译器转为
pc->~Complex();
operator delete(pc);//里面调用free
# Ctor & Dtor 直接调用
自己无法直接调用构造函数
string* pstr = new string;
//! pstr->string::string("jjhou");
//[Error] 'class std::basic_string<char>' has no member named 'string'
//! pstr->~string(); //crash -- 其語法語意都是正確的, crash 只因為上一行被 remark 起來嘛.
# array new, array delete
Complex* pca = new Complex[3];
//调用3次ctor
delete[] pca; //调用3次dtor
特别注意加[]
```bash
|cookie |
pca-> |Complex object |
|Complex object |
|Complex object |
size_t size = 3;
{
//模擬 memory pool 的作法, array new + placement new.
A* buf = (A*)(new char[sizeof(A)*size]);//3次default ctor
A* tmp = buf;
for(int i = 0; i < size; ++i)
new (tmp++) A(i); //3次有参ctor
delete [] buf; //3次dtor 逆序
}
# array size, in memory block
int* pi = new int[10];
delete pi;
pi指向第一个数组,数组上边的一块内存用来存放数组长度。
void* operator new(size_t size) {
if (size == 0) size = 1;
void* ptr = malloc(size);
if (ptr == nullptr) {
std::cout << "ERROR NEW!" << std::endl;
}
std::cout << "NEW Memory Size = " << size << " address = " << ptr << std::endl;
return ptr;
}
void* operator new[](size_t size) {
if (size == 0) size = 1;
void* ptr = malloc(size);
if (ptr == nullptr) {
std::cout << "ERROR NEW[]!" << std::endl;
}
std::cout << "NEW[] Memory Size = " << size << " address = " << ptr << std::endl;
return ptr;
}
void operator delete(void* ptr) {
std::cout << "DELETE " << ptr << std::endl;
if (ptr) free(ptr);
}
void operator delete[](void* ptr) {
std::cout << "DELETE[] " << ptr << std::endl;
if (ptr) free(ptr);
}
//An allocation function shall be a class member function or a global function; a program is ill-formed if an allocation function is declared in a namespace scope other than global scope or declared static in global scope.
//分配函数应为类成员函数或全局函数;如果分配函数在非全局范围的命名空间范围内声明,或在全局范围内声明为静态,则程序是格式错误的。
# placement new
- placement new 允许我们将object建构于allocated memory中。
- 没有placement delete,因为placement new根本没有分配memory
char* buf = new char[sizeof(Complex)*3];
Complex* pc = new(buf)Complex(1, 2);
//||编译器转为
void* mem = operator new(sizeof(Complex), buf);//operator new(size_t,void* loc){return loc;}
pc = static_cast<Complex*>(mem);
pc->Complex::Complex(1, 2);
# pre-class allocator
# 第一版
class Screen {
public:
Screen(int x) : i(x) { };
void* operator new(size_t);
void operator delete(void*, size_t);
private:
Screen* next;
static Screen* freeStore;
static const int screenChunk;
private:
int i;
};
Screen* Screen::freeStore = 0;
const int Screen::screenChunk = 24;
void* Screen::operator new(size_t size)
{
Screen *p;
if (!freeStore) {
//linked list 是空的,所以攫取一大塊 memory
//以下呼叫的是 global operator new
size_t chunk = screenChunk * size;
freeStore = p =
reinterpret_cast<Screen*>(new char[chunk]);
//將分配得來的一大塊 memory 當做 linked list 般小塊小塊串接起來
for (; p != &freeStore[screenChunk-1]; ++p)
p->next = p+1;
p->next = 0;
}
p = freeStore;
freeStore = freeStore->next;
return p;
}
void Screen::operator delete(void *p, size_t)
{
//將 deleted object 收回插入 free list 前端
(static_cast<Screen*>(p))->next = freeStore;
freeStore = static_cast<Screen*>(p);
}
void test_per_class_allocator_1()
{
size_t const N = 100;
Screen* p[N];
for (int i=0; i< N; ++i)
p[i] = new Screen(i);
for (int i=0; i< N; ++i)
delete p[i];
}
# 第二版
没有使用多余的指针
class Airplane { //支援 customized memory management
private:
struct AirplaneRep {
unsigned long miles;
char type;
};
private:
union {
AirplaneRep rep; //此針對 used object
Airplane* next; //此針對 free list
};
public:
unsigned long getMiles() { return rep.miles; }
char getType() { return rep.type; }
void set(unsigned long m, char t)
{
rep.miles = m;
rep.type = t;
}
public:
static void* operator new(size_t size);
static void operator delete(void* deadObject, size_t size);
private:
static const int BLOCK_SIZE;
static Airplane* headOfFreeList;
};
Airplane* Airplane::headOfFreeList;
const int Airplane::BLOCK_SIZE = 512;
void* Airplane::operator new(size_t size)
{
//如果大小錯誤,轉交給 ::operator new()
if (size != sizeof(Airplane))
return ::operator new(size);
Airplane* p = headOfFreeList;
//如果 p 有效,就把list頭部移往下一個元素
if (p)
headOfFreeList = p->next;
else {
//free list 已空。配置一塊夠大記憶體,
//令足夠容納 BLOCK_SIZE 個 Airplanes
Airplane* newBlock = static_cast<Airplane*>
(::operator new(BLOCK_SIZE * sizeof(Airplane)));
//組成一個新的 free list:將小區塊串在一起,但跳過
//#0 元素,因為要將它傳回給呼叫者。
for (int i = 1; i < BLOCK_SIZE-1; ++i)
newBlock[i].next = &newBlock[i+1];
newBlock[BLOCK_SIZE-1].next = 0; //以null結束
// 將 p 設至頭部,將 headOfFreeList 設至
// 下一個可被運用的小區塊。
p = newBlock;
headOfFreeList = &newBlock[1];
}
return p;
}
// operator delete 接獲一塊記憶體。
// 如果它的大小正確,就把它加到 free list 的前端
void Airplane::operator delete(void* deadObject,
size_t size)
{
if (deadObject == 0) return;
if (size != sizeof(Airplane)) {
::operator delete(deadObject);
return;
}
Airplane *carcass =
static_cast<Airplane*>(deadObject);
carcass->next = headOfFreeList;
headOfFreeList = carcass;
}
//-------------
void test_per_class_allocator_2()
{
cout << sizeof(Airplane) << endl; //8
size_t const N = 100;
Airplane* p[N];
for (int i=0; i< N; ++i)
p[i] = new Airplane;
//輸出前 10 個 pointers, 用以比較其間隔
for (int i=0; i< 10; ++i)
cout << p[i] << endl;
for (int i=0; i< N; ++i)
delete p[i];
}
# 第三版 static allocator
class allocator
{
private:
struct obj {
struct obj* next; //embedded pointer
};
public:
void* allocate(size_t);
void deallocate(void*, size_t);
void check();
private:
obj* freeStore = nullptr;
const int CHUNK = 5; //小一點方便觀察
};
void* allocator::allocate(size_t size)
{
obj* p;
if (!freeStore) {
//linked list 是空的,所以攫取一大塊 memory
size_t chunk = CHUNK * size;
freeStore = p = (obj*)malloc(chunk);
//cout << "empty. malloc: " << chunk << " " << p << endl;
//將分配得來的一大塊當做 linked list 般小塊小塊串接起來
for (int i=0; i < (CHUNK-1); ++i) { //沒寫很漂亮, 不是重點無所謂.
p->next = (obj*)((char*)p + size);
p = p->next;
}
p->next = nullptr; //last
}
p = freeStore;
freeStore = freeStore->next;
//cout << "p= " << p << " freeStore= " << freeStore << endl;
return p;
}
void allocator::deallocate(void* p, size_t)
{
//將 deleted object 收回插入 free list 前端
((obj*)p)->next = freeStore;
freeStore = (obj*)p;
}
void allocator::check()
{
obj* p = freeStore;
int count = 0;
while (p) {
cout << p << endl;
p = p->next;
count++;
}
cout << count << endl;
}
class Foo {
public:
long L;
string str;
static allocator myAlloc;
public:
Foo(long l) : L(l) { }
static void* operator new(size_t size)
{ return myAlloc.allocate(size); }
static void operator delete(void* pdead, size_t size)
{ return myAlloc.deallocate(pdead, size); }
};
allocator Foo::myAlloc;
# 第四版 micro for static allocator
// DECLARE_POOL_ALLOC -- used in class definition
#define DECLARE_POOL_ALLOC() \
public: \
void* operator new(size_t size) { return myAlloc.allocate(size); } \
void operator delete(void* p) { myAlloc.deallocate(p, 0); } \
protected: \
static allocator myAlloc;
// IMPLEMENT_POOL_ALLOC -- used in class implementation file
#define IMPLEMENT_POOL_ALLOC(class_name) \
allocator class_name::myAlloc;
// in class definition file
class Foo {
DECLARE_POOL_ALLOC()
public:
long L;
string str;
public:
Foo(long l) : L(l) { }
};
//in class implementation file
IMPLEMENT_POOL_ALLOC(Foo)
第二讲 std::allocator
第三讲 malloc/free
第四讲 other allocators
第五讲 loki::alloctor
← 基础 第二讲allocator →