个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

  • CPlusPlus

  • Lua技术栈

  • edoyun

  • 内存管理

    • 第一讲memory primitivates
      • 前言
      • primitives基础工具
      • new, delete expression
        • new expression
        • delete expression
        • Ctor & Dtor 直接调用
      • array new, array delete
        • array size, in memory block
      • placement new
      • pre-class allocator
        • 第一版
        • 第二版
        • 第三版 static allocator
        • 第四版 micro for static allocator
    • 第二讲allocator
  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • 内存管理
Agnes001
2022-01-16

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

编辑此页
#memory
基础
第二讲allocator

← 基础 第二讲allocator →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式