自定义内存操作的意义:
- 降低 malloc 调用次数,提高内存空间利用率(每次 malloc 会携带上下 cookies[8bytes]标记)
- 降低 malloc 调用次数,提高内存管理速度
实现一 [ref. C++ Primer 3/e,p.765]
#include <cstddef>
#include <iostream>
using namespace std;
class Screen {
public:
Screen(int x) : i(x)
{ }
int get()
{
return i;
}
// 默认 static
void *operator new(size_t);
// 默认 static
void operator delete(void*, size_t);
private:
Screen *next; // 这种设计会引发多耗用一个 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 是空的,所以申请一大块
size_t chunk = screenChunk * size;
freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
// 将一大块分割,当作 linked_list 串起来
for (; p!= &freeStore[screenChunk-1]; ++p)
p->next =p + 1;
p->next = 0;
}
p = freeStore;
freeStore = freeStore->next;
return p;
}
// 并为将内存归还给系统,任由 Screen 接管(不算是内存泄露)
void Screen::operator delete(void* p, size_t)
{
// 讲 deleted object 插回 free list 前端
(static_cast<Screen*>(p))->next = freeStore;
freeStore = (static_cast<Screen*>(p));
}
void func_1()
{
cout << "==== " << "Screen::operator new" << " ====" << endl;
cout << sizeof(Screen) << endl;
size_t const N = 100;
Screen *p[N];
for (size_t i=0; i<N; ++i)
p[i] = new Screen(i);
for (size_t i=0; i<10; ++i)
cout << p[i] << endl;
for (size_t i=0; i<N; ++i)
delete p[i];
}
void func_2()
{
cout << "==== " << "::operator new" << " ====" << endl;
cout << sizeof(Screen) << endl;
size_t const N = 100;
Screen *p[N];
for (size_t i=0; i<N; ++i)
p[i] = ::new Screen(i);
for (size_t i=0; i<10; ++i)
cout << p[i] << endl;
for (size_t i=0; i<N; ++i)
:: delete p[i];
}
int main()
{
func_1();
func_2();
return 0;
}
输出:【以下输出证明自定义内存管理提高了空间利用率】
==== Screen::operator new ==== // 内存间隔 8
8
0x10080e8
0x10080f0
0x10080f8
0x1008100
0x1008108
0x1008110
0x1008118
0x1008120
0x1008128
0x1008130
==== ::operator new ==== // 内存间隔 16, 包含 8 bytes cookies (上、下)
8
0x1001630
0x10084d0
0x10084e0
0x10084f0
0x1008500
0x1008510
0x1008520
0x1008530
0x1008540
0x1008550
实现二 [ref.Effective C++ 2e,item10]
#include <cstddef>
#include <iostream>
using namespace std;
class Airplane {
private:
struct AirplaneRep
{
unsigned long miles;
char type;
};
private:
union
{
AirplaneRep rep; // 此处针对使用中的 object
Airplane *next; // 此处针对 free list 上的 object
};
public:
unsigned long getMiles()
{
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;
};
const int Airplane::BLOCK_SIZE = 512;
Airplane *Airplane::headOfFreeList = nullptr;
void *Airplane::operator new(size_t size)
{
// 如果大小有误,转交给 ::operator new [继承时发生]
if (size != sizeof (Airplane))
return ::operator new(size);
Airplane *p = headOfFreeList;
if (p) // 如果 p 有效,就把 list 头部下移一个元素
{
headOfFreeList = p->next;
}
else
{
// free list 已空,申请(分配)一大块内存
Airplane *newBlock = static_cast<Airplane*>(::operator new(BLOCK_SIZE *sizeof(Airplane)));
// 将小块串成一个 free list, 但跳过#0, 因它将被传回当作本次成果
for (int i=1; i<BLOCK_SIZE; ++i)
newBlock[i].next = &newBlock[i+1];
newBlock[BLOCK_SIZE-1].next = 0; // 结束 list
p = newBlock;
headOfFreeList = &newBlock[1];
}
return p;
}
// operator delete 接收一个内存块,如果大小正确,就把它加到 free list 前端
void Airplane::operator delete(void *deadObject, size_t size)
{
if (deadObject == 0)
return;
// 如果大小有误,转交给 ::operator delete [继承时发生]
if (size != sizeof(Airplane))
{
::operator delete(deadObject);
return;
}
Airplane *carcass = static_cast<Airplane*>(deadObject);
carcass->next = headOfFreeList;
headOfFreeList = carcass;
}
void func_1()
{
cout << "==== " << "Airplane::operator new" << " ====" << endl;
size_t const N =100;
Airplane *p[N];
for (size_t i=0; i<N; ++i)
p[i] = new Airplane;
// 随机测试 object 是否正常
p[1]->set(100, 'A');
p[5]->set(1000, 'B');
p[9]->set(10000, 'C');
// 输出前 10 个 pointer, 用以比较其间隔
for (size_t i=0; i<10; ++i)
cout << p[i] << endl;
for (size_t i=0; i<N; ++i)
delete p[i];
}
void func_2()
{
cout << "==== " << "::operator new" << " ====" << endl;
size_t const N =100;
Airplane *p[N];
for (size_t i=0; i<N; ++i)
p[i] = ::new Airplane;
// 随机测试 object 是否正常
p[1]->set(100, 'A');
p[5]->set(1000, 'B');
p[9]->set(10000, 'C');
// 输出前 10 个 pointer, 用以比较其间隔
for (size_t i=0; i<10; ++i)
cout << p[i] << endl;
for (size_t i=0; i<N; ++i)
::delete p[i];
}
int main()
{
cout << sizeof(Airplane) << endl; // 注意输出,考虑字节对齐 !!
func_1();
func_2();
return 0;
}
输出:
8
==== Airplane::operator new ==== // 内存间隔 8
0xed80e8
0xed80f0
0xed80f8
0xed8100
0xed8108
0xed8110
0xed8118
0xed8120
0xed8128
0xed8130
==== ::operator new ==== // 内存间隔 16, 包含 8 bytes cookies (上、下)
0xed1630
0xed90f0
0xed9100
0xed9110
0xed9120
0xed9130
0xed9140
0xed9150
0xed9160
0xed9170
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。