目录
一、对象池简介
1.1 池化技术
1.2 什么是对象池
1.3 对象池分配策略
二、C++ new和delete运算符重载
三、实现一个对象池框架
3.1 策略接口
四、实现几种对象池的分配策略
4.1 数组策略
4.2 堆策略
编辑
4.3 栈策略
4.4 区块策略
一、对象池简介
1.1 池化技术
线程池、连接池、内存池
池化技术共同点
提前创建资源,以备不时之需时重复利用,极致的提升性能。
由于在实际应用里分配内存、创建进程、线程,都会涉及到一些系统调用,系统调用需要导致程序从用户态切换到内核态,是非常耗时的操作。因此,当程序中需要频繁的进行内存申请释放,进程、线程创建销毁等操作时,通常会使用内存池、进程池、线程池等技术来提升程序的性能。
1.2 什么是对象池
对象池简介
对象池的实现和内存池的实现原理很像:都是-开始申请大内存空间, 然后把大内存分配成小内存空间,当需要使用的时候直接分配使用,不再向系统申请内存空间,也不直接释放内存空间。使用完之后都是放回池子里。
注意
对象池其实就是一种特殊的内存池,仅分配固定大小的内存。
1.3 对象池分配策略
● 基于数组的策略
● 基于堆的策略
● 基于栈的策略
● 基于区块的策略
课程里我们会实现以上几种对象池的分配策略,从最简单的数组策略到比较复杂的区块策略。每种策略都有各自的特点和适用场景。
二、C++ new和delete运算符重载
class A
{
public:void * operator new(size_t n){std::cout << "A new" << std::endl; return ::malloc(n);}void operator delete(void * p){std::cout << "A delete" << std::endl;::free(p);}
};
三、实现一个对象池框架
3.1 策略接口
template <typename T>
class Allocator {
public:virtual T * allocate() = 0;virtual void deallocate(T * p) = 0;
};
策略接口函数:
allocate:分配内存
deallocate:回收内存
现在创建和析构对象不需要用new和free了,而是用对象池的创建和析构函数。
// a.h#pragma once
#include <iostream>
#include "object_pool.h"
#include "malloc_allocator.h"using namespace huan::object;class A
{
private:typedef ObjectPool<A, MallocAllocator<A>> ObjectPool;static ObjectPool pool;
public:A(){std::cout << "A construct" << std::endl;}~A(){std::cout << "A destruct" << std::endl;}void * operator new(size_t n){std:: cout << "A new" << std::endl;return pool.allocate(n);}void operator delete(void * p){std::cout << "A delete" << std::endl;pool.deallocate(p);}
};A::ObjectPool A::pool;
// object_pool.h#pragma once#include <stdexcept>namespace huan
{namespace object{template <typename T, typename Allocator>class ObjectPool{public:ObjectPool() = default;~ObjectPool() = default;void * allocate(size_t n){if (sizeof(T) != n)throw std::bad_alloc();return m_allocator.allocate();}void deallocate(void * p){m_allocator.deallocate(static_cast<T *>(p));}private:Allocator m_allocator;};}
}
// malloc_allocator.h#pragma once#include "allocator.h"namespace huan
{namespace object{template <typename T>class MallocAllocator : public Allocator<T>{public:MallocAllocator() = default;~MallocAllocator() = default;virtual T * allocate(){auto p = ::malloc(sizeof(T));return reinterpret_cast<T *>(p);}virtual void deallocate(T * p){::free(p);}};}
}
// allocator.h#pragma oncenamespace huan
{namespace object{template <typename T>class Allocator{public:virtual T * allocate() = 0;virtual void deallocate(T * p) = 0;};}
}
四、实现几种对象池的分配策略
4.1 数组策略
#include <src/a.h>int main()
{A * arr[max_size] = { nullptr };for (int i = 0; i < max_size; i++){A * a = new A();arr[i] = a;}for (int i = 0; i < max_size; i++){delete arr[i];}return 0;
}
#pragma once#include "allocator.h"namespace huan
{namespace object{template <typename T, int N>class ArrayAllocator : public Allocator<T>{public:ArrayAllocator(){for (int i = 0; i < N; i++){m_used[i] = false;}}~ArrayAllocator() = default;virtual T * allocate(){for (int i = 0; i < N; i++){if (!m_used[i]){m_used[i] = true;return reinterpret_cast<T *>(&m_data[sizeof(T) * i]);}}// 如果没找到throw std::bad_alloc();}virtual void deallocate(T * p){auto i = ((unsigned char *)p - m_data) / sizeof(T);m_used[i] = false;}private:unsigned char m_data[sizeof(T) * N];bool m_used[N];};}
}
注意:基于数组的时间复杂度高 O(n)
4.2 堆策略
使用大根堆,heap第一个位置总是空闲的。在插入一个对象后,堆会重新把一个没有使用的位置放到第一位
// heap_allocator.h#include <algorithm>
#include "allocator.h"namespace huan
{namespace object{template <typename T, int N>class HeapAllocator : public Allocator<T>{public:enum State{FREE = 1,USED = 0,};struct Entry{State state; // 状态T * p; // 对象指针bool operator < (const Entry & other) const{return state < other.state;}};HeapAllocator(){m_available = N;for (int i = 0; i < N; i++){m_entry[i].state = FREE; // 未使用m_entry[i].p = reinterpret_cast<T *>(&m_data[sizeof(T) * i]);}// 调用生成大堆的算法std::make_heap(m_entry, m_entry + N);}~HeapAllocator() = default;virtual T * allocate(){if (m_available <= 0)throw std::bad_alloc();Entry e = m_entry[0];std::pop_heap(m_entry, m_entry + N);m_available--;m_entry[m_available].state = USED;m_entry[m_available].p = nullptr;return e.p;}virtual void deallocate(T * p){if (p == nullptr || m_available >= N)return;m_entry[m_available].state = FREE;m_entry[m_available].p = reinterpret_cast<T *>(p);m_available++;std::push_heap(m_entry, m_entry + N);}private:unsigned char m_data[sizeof(T) * N];Entry m_entry[N];int m_available;};}
}
时间复杂度 O(log n)