目录
1.容器内存空间配置器的概念
2. Vector List deque的内存分配策略
2.1 Vector的内存分配策略模拟
2.2 List的内存分配策略
2.3 deque的内存分配策略
3.内存池技术及其仿真
Allocator:对容器与内存分布进行管理的承担者
#include
#include
#include
#include
using namespace std;
//空间配置器的基类模板
template
struct Allocator_base {
typedef _Ty value_type;
};
template
struct Allocator_base {
typedef _Ty value_type;
};
//空间配置器的类模板设计
template
class Allocator :public Allocator_base<_Ty> {
public:
//内嵌数据类型表
typedef typename std::size_t size_type;
typedef typename std::ptrdiff_t difference_type;
typedef _Ty* pointer;
typedef const _Ty* const_pointer;
typedef _Ty& reference;
typedef const _Ty& const_reference;
typedef Allocator_base<_Ty> _Mybase;
typedef typename _Mybase::value_type value_type;
//配置器类型的嵌入类型
template
struct rebind {
typedef Allocator<_U>other;
};
//构造函数
Allocator()throw() {
}
Allocator(const Allocator&)throw() {}
//可以接受不同类型的其他allocator的拷贝构造
template
Allocator(const Allocator<_otherAll>&)throw() {}
~Allocator()throw()
{
}
//请求内存空间
pointer allocate(size_type num, typename Allocator<_Ty>::const_pointer hint = 0) {
//显示一下内存空间发呢配信息
static int i = 0;
i++;
cout << endl;
cout << "第" << i << "次分配" << "-----------------------" << endl;
cout << "本次需要分配可容纳" << num << "个元素空间" << endl;
return (pointer)(::operator new(num * sizeof(_Ty)));
}
//在已经请求的内存空间中构造容器元素对象:operator new之后,用placement new指向
void construct(pointer p, const_reference value) {
new(p)_Ty(value);
}
//析构容器元素对象
void destroy(pointer p) {
p->~_Ty();
}
//释放已有的内存空间
void deallocate(pointer p, size_type size) {
::operator delete(p);
}
};
//调用
template
void print(vector<_T, Allocator<_T>>& iv) {
cout << "现在空间可容纳" << iv.capacity() << "个元素";
cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
cout << "容器中的元素数据:";
for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
cout << endl;
}
int main() {
int a[] = { 1,2,3 };
vector>vec(a, a + 3);
print(vec);
for (int i = 1; i < 10; i++) {
vec.push_back(10 * i);
print(vec);
}
return 0;
}
可以看到每次分配的内存空间均为上次的1.5倍,这也是VS编译器所采取的策略。
不同C++编译器分配内存策略不同,例如g++就是2倍。
对之前的代码做以下修改,变为list的,其他代码保持不变:
//调用
template
void print(list<_T, Allocator<_T>>& iv) {
//cout << "现在空间可容纳" << iv.capacity() << "个元素";
cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
cout << "容器中的元素数据:";
for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
cout << endl;
}
int main() {
int a[] = { 1,2,3 };
//vector>vec(a, a + 3);
list>myList(a, a + 3);
print(myList);
for (int i = 1; i < 5; i++) {
myList.push_back(10 * i);
print(myList);
}
return 0;
}
可以看到list的分配内存方式是一个一个分配的,需要一个就分配一个,不留余量。
//调用
template
void print(deque<_T, Allocator<_T>>& iv) {
//cout << "现在空间可容纳" << iv.capacity() << "个元素";
cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
cout << "容器中的元素数据:";
for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
cout << endl;
}
int main() {
int a[] = { 1,2,3 };
//vector>vec(a, a + 3);
//list>myList(a, a + 3);
deque>deq(a, a + 3);
print(deq);
for (int i = 1; i < 200; i++) {
deq.push_back(i);
//print(deq);
}
return 0;
}
deque每次分配固定大小内存,每次4个,逐次累加。
#include
#define MEMPOOL_ALIGNMENT 8
using namespace std;
//内存块
template
struct MemoryBlock{
//表域
int nSize;//内存块大小,以字节为单位
int nFree;//表示内存剩余可分配的单位
int nFirst;//首个剩余单位的序号
MemoryBlock* pNext;
char aData[1];//内存空间开始位置标记
MemoryBlock(int nUnitSize, int nUninAmount) :
nSize(nUnitSize* nUninAmount), nFree(nUninAmount - 1), nFirst(1), pNext(nullptr)
{
//下一个可以分配的单位序号需要记录当前单元的强两个字节
char* ppData = aData;
cout << "存储区首地址ppData=" << (int)*ppData << endl;
for (int i = 1; i < nUninAmount; i++) {
//在当前存储单位空间 存储下一个可分配的单位序号
(*(unsigned short*)ppData) = i;
ppData += nUnitSize;
}
cout << "内存块的构造函数被调用了" << endl;
}
//nUnitSize:存储单位大小
//nUnitAmount:内存块的规模(数量)
void* operator new(size_t, int nUnitSize, int nUnitAmount) {
cout << "分配内存空间并创建MemoryBlock" << endl;
return ::operator new(sizeof(MemoryBlock) + nUnitSize * nUnitAmount);
}
void operator delete(void* pBlock) {
cout << "调用了内存的析构" << endl;
}
};
//内存池 Mempool
template
struct MemoryPool
{
int nInitSize;
int nGrowSize;
int nUnitSize;
MemoryBlock<_T>* pBlock;
MemoryPool(int _nGrowSize = 10, int _nInitSize = 3) {
cout << "调用了内存池的构造函数" << endl;
nInitSize = _nInitSize;
nGrowSize = _nGrowSize;
pBlock = nullptr;
nUnitSize = (sizeof(_T));
//纯出单位的大小调整
if (sizeof(_T) > 4) {
//8字节对齐
nUnitSize = (sizeof(_T) + (MEMPOOL_ALIGNMENT - 1)) &
~(MEMPOOL_ALIGNMENT - 1);
}
else {
if (sizeof(_T) < 2) { nUnitSize = 2; }
else { nUnitSize = 4; }
}
}
~MemoryPool() {
MemoryBlock<_T>* pMyBlock = pBlock;
while (pMyBlock != nullptr) {
pMyBlock = pMyBlock->pNext;
delete(pMyBlock);
}
cout << "调用了内存池的析构函数" << endl;
}
void* allocate(size_t num) {
for (int i = 0; i < num; i++) {
if (pBlock == nullptr) {
//创建首个内存块
pBlock = (MemoryBlock<_T>*)new(nUnitSize, nInitSize)MemoryBlock<_T>(nUnitSize, nInitSize);
return (void*)pBlock->aData;
}
//为内存寻求合适的内存块
MemoryBlock<_T>* pMyBlock = pBlock;
while (pMyBlock != nullptr && pMyBlock->nFree == 0) {
pMyBlock = pMyBlock->pNext;
}
if (pMyBlock != nullptr) {
cout << "内存空间已经找到,First=" << pMyBlock->nFirst << endl;
char* pFree = pMyBlock->aData + pMyBlock->nFirst * nUnitSize;
pMyBlock->nFirst = *((unsigned short*)pFree);
pMyBlock->nFree--;
return (void*)pFree;
}
else {
//说明内存用完了
if (nGrowSize == 0) {
return nullptr;
}
cout << "分配新内存" << endl;
pMyBlock = (MemoryBlock<_T>*)new (nUnitSize, nGrowSize)MemoryBlock<_T>(nUnitSize, nGrowSize);
if (pMyBlock == nullptr) {
return nullptr;
}
//如果成功那么,将新内存插入链表
pMyBlock->pNext = pBlock;
pBlock = pMyBlock;
return (void*)pMyBlock->aData;
}
}
}
void free(void* pFree) {
cout << "释放存储单位的空间" << endl;
//找到p所在的内存块
MemoryBlock<_T>* pMyBlock = pBlock;
MemoryBlock<_T>* PreBlock = nullptr;
while (pMyBlock != nullptr && (pBlock->aData > pFree)
|| pMyBlock->aData + pMyBlock->nSize) {
PreBlock = pMyBlock;
pMyBlock = pMyBlock->pNext;
}
//该内存在本内存池中的指向位置
if (pMyBlock != nullptr) {
//修改数组链表
*((unsigned short*)pFree) = pMyBlock->nFirst;
pMyBlock->nFirst = (unsigned short)((unsigned long)pFree - (unsigned long)pMyBlock->aData) / nUnitSize;
pMyBlock->nFree++;
//判断是否需要向操作系统释放内存
if (pMyBlock->nSize == pMyBlock->nFree * nUnitSize) {
delete(pMyBlock);
}
else {
PreBlock = pMyBlock->pNext;
pMyBlock->pNext = pBlock;
pBlock = pMyBlock;
}
}
}
};
class UserCls {
int s;
double s1;
double s2;
public:
UserCls(int x) :s(x) {
cout << "调用了UserCls的构造函数" << endl;
}
int get() { return s; }
~UserCls()
{
cout << "调用了UserCls的析构函数" << endl;
}
};
int main() {
MemoryPoolM_Pool;
UserCls* dp1 = (UserCls*)M_Pool.allocate(1);
cout << "dp1=" << dp1 << endl;
new(dp1)UserCls(111);
cout << "dp1中的数据是" << dp1->get() << endl;
cout << endl;
UserCls* dp2 = (UserCls*)M_Pool.allocate(1);
cout << "dp2=" << dp2 << endl;
new(dp2)UserCls(222);
cout << "dp2中的数据是" << dp2->get() << endl;
cout << endl;
UserCls* dp3 = (UserCls*)M_Pool.allocate(1);
cout << "dp3=" << dp3 << endl;
new(dp3)UserCls(333);
cout << "dp3中的数据是" << dp3->get() << endl;
cout << endl;
UserCls* dp4 = (UserCls*)M_Pool.allocate(1);
cout << "dp4=" << dp4 << endl;
new(dp4)UserCls(444);
cout << "dp4中的数据是" << dp4->get() << endl;
cout << endl;
UserCls* dp5 = (UserCls*)M_Pool.allocate(1);
cout << "dp5=" << dp5 << endl;
new(dp5)UserCls(555);
cout << "dp5中的数据是" << dp5->get() << endl;
cout << endl;
return 0;
}