先聊聊内存池吧,c++把内存管理的职责交给了我们,虽然给我们带来了很多麻烦,但是同样也给了我们很大的发挥空间,对于一个长期运行的系统来说,在一段时间后,堆的内存碎片会随着我们不断的申请和释放空间而越来越多,这就造成了我们的申请内存的消耗越来越大,对于这种问题,我们可以用内存池来解决。
c++内存池的关键就在于重载new操作符,看一个简单的例子:
#ifndef __POOL_OBJECT_H__
#define __POOL_OBJECT_H__
class CMemPoolObject
{
protected:
CMemPoolObject() = delete;
CMemPoolObject(int a);
public:
~CMemPoolObject();
void* operator new(size_t size);
static CMemPoolObject* CreateInstance(int a);
int getA();
void setA(int a);
private:
int a;
public:
static char* mpCurrAddr;
};
#endif
#include
#include
#include "mempoolobject.h"
char* CMemPoolObject::mpCurrAddr = NULL;
CMemPoolObject::CMemPoolObject(int a)
{
this->a = a;
}
CMemPoolObject::~CMemPoolObject()
{
}
void *CMemPoolObject::operator new(size_t size) {
return (void*)mpCurrAddr;
}
int CMemPoolObject::getA()
{
return a;
}
void CMemPoolObject::setA(int a)
{
this->a = a;
}
CMemPoolObject* CMemPoolObject::CreateInstance(int a)
{
return new CMemPoolObject(a);
}
//
// main.cpp
// Demo
//
// Created by DGuco on 17/6/22.
// Copyright © 2017年 DGuco. All rights reserved.
//
#include
#include "mempoolobject.h"
#define MEM_SIZE 1024 * 10
int main(int argc, const char * argv[]) {
static char acBuffre[MEM_SIZE] = {0};
CMemPoolObject::mpCurrAddr = acBuffre;
CMemPoolObject* object = CMemPoolObject::CreateInstance(1);
std::cout << "a = %d" << object->getA() << std::endl;
printf("&object %lld \n",object);
printf("&acBuffre %lld \n",acBuffre);
}
#include "mempoolobject.h"
#define MEM_SIZE 1024 * 10
int main(int argc, const char * argv[]) {
static char acBuffre[MEM_SIZE] = {0};
CMemPoolObject::mpCurrAddr = acBuffre;
CMemPoolObject* object = CMemPoolObject::CreateInstance(1);
std::cout << "a = %d" << object->getA() << std::endl;
printf("&object %lld \n",object);
printf("&acBuffre %lld \n",acBuffre);
}
通过重载new操作符我们就可以控制对象产生的方式和对象所在的位置,这里我们简单的把对象产生在事先申请好的静态存储区,这里有几点要注意,首先是析构函数,这里我什么都没做,因为内存在静态存储区,如果我们重载new操作符申请内存通过其他方式比如malloc等,注意要在析构函数中释放掉内存,或者重载delete操作符释放掉也可以。还有我们这里把构造函数生命成protect,是为了防止在栈上生成对象,因为此时不会调用new操作符,所以对象也不会生成在我们预期的地址上。这里只是简单的说下内存池的原理,具体的详细的实现推荐一篇文章吧,写的比我好:点击打开链接
下面我们利用这个特性和共享内存。基于c++内存池,共享内存和信号量实现高速的进程间通信队列,支持单进程读单进程写,单进程多进程写,多进程读单进程写,多进程读多进程写。
shmmqueue.h shmmqueue.cpp shm_rwlock.h shm_rwlock.cpp
基本原理是就是把消息管理类申请到开辟好的共享内存上,共享内存的大小要大于消息管理类自身的大小,剩余的部分用来放消息数据。内存上是一个环形的管理方式,内存池技术实现原理基于此篇文章:点击打开链接。 写的时候移动end索引,读的时候移动begin索引,保证了在单进程读和单进程写的时候是线程安全的,多进程读多进成写时利用信号量集(一个读信号和写信号)实现进程间的共享内存读写锁来保证多进程安全。
更详细的内容介绍以及测试结果,见github地址:点击打开链接