目录

内存池使用手册

1. 概述

这个内存池库使用内存池技术提供了一种自定义内存管理解决方案。它旨在通过预先分配一大块内存并在其中管理较小的对象,来减少频繁内存分配和释放的开销。

2. 文件及其功能

memorypool.h

  • 常量定义

    • FREE_LIST_COUNT:定义内存池中自由链表的数量,值设置为 16。
    • BLOCK_SIZE:指定内存池分配的每个内存块的大小,默认值为 4096 字节。
    • BASE_OBJ_SIZE:内存池管理的对象的基本大小,设置为 8 字节。
    • MAX_OBJ_SIZE:内存池可以处理的对象的最大大小。大于这个大小的对象将使用标准的operator new进行分配,值为 128 字节。
  • MemoryPool

    • 这个类封装了内存池的核心功能,包括构造函数、析构函数,以及用于内存初始化、分配和释放的方法。
    • init(size_t size):初始化内存池以处理给定大小的对象。
    • allocate():为一个对象分配一块内存。
    • deallocate(void* obj):释放先前分配的对象,并将其添加到自由列表中。
    • initMemoryPool():初始化内存池中的所有自由列表。
    • getFreeList(size_t index):返回对特定自由列表的引用。
    • retrieve(size_t size):为给定大小的对象检索一块内存。如果大小大于MAX_OBJ_SIZE,则使用标准的operator new
    • revert(void* obj, size_t size):归还先前分配的对象。如果对象大小大于MAX_OBJ_SIZE,则使用标准的operator delete
  • 模板函数

    • newElement<T>():使用内存池为类型为T的对象分配内存,并在原地构造该对象。
    • deleteElement<T>(T* obj):析构类型为T的对象,并使用内存池释放其内存。

memory.cpp

  • 静态内存池数组

    • 定义了一个名为memoryPoolMemoryPool对象数组,大小为FREE_LIST_COUNT
  • MemoryPool类的实现

    • 这里实现了MemoryPool类的构造函数、析构函数和所有成员函数。

3. 使用方法

包含头文件

要在项目中使用内存池,需要包含memorypool.h头文件:

cpp 复制代码
#include "memorypool.h"

初始化内存池

在使用内存池之前,需要对其进行初始化:

cpp 复制代码
MemoryPool::initMemoryPool();

分配和释放内存

可以使用模板函数newElementdeleteElement来分配和释放对象:

cpp 复制代码
// 分配一个MyClass类型的对象
MyClass* obj = newElement<MyClass>();

// 使用该对象......

// 释放该对象
deleteElement(obj);

手动分配和释放

如果更喜欢直接使用MemoryPool类的方法,可以这样做:

cpp 复制代码
// 为大小为sizeof(MyClass)的对象分配内存
void* rawObj = MemoryPool::retrieve(sizeof(MyClass));
MyClass* myObj = new(rawObj) MyClass();

// 使用该对象......

// 析构对象并释放内存
myObj->~MyClass();
MemoryPool::revert(rawObj, sizeof(MyClass));

4. 注意事项

  • 对象大小限制 :大于MAX_OBJ_SIZE的对象将使用标准的operator newoperator delete进行分配。
  • 初始化 :在进行任何内存分配之前,必须使用MemoryPool::initMemoryPool()初始化内存池。
  • 正确销毁:使用内存池时,确保在释放对象内存之前正确地析构对象。

5. 未来改进方向

  • 线程安全性:添加线程安全机制,使内存池适用于多线程应用程序。
  • 动态配置 :使诸如FREE_LIST_COUNTBLOCK_SIZE等常量在运行时可配置。

6. 源码

memory.h 复制代码
#ifndef _MEMORYPOOL_MEMORYPOOL_H_
#define _MEMORYPOOL_MEMORYPOOL_H_

static const size_t FREE_LIST_COUNT = 16;
static const size_t BLOCK_SIZE = 4096;
static const size_t BASE_OBJ_SIZE = 8;
static const size_t MAX_OBJ_SIZE = 128;

class MemoryPool
{
public:
	MemoryPool();
	~MemoryPool();

	void init(size_t size);
	void* allocate();
	void deallocate(void* obj);

	static void initMemoryPool();
	static MemoryPool& getFreeList(size_t index);

	static void* retrieve(size_t size);
	static void revert(void* obj, size_t size);

private:
	size_t m_blockSize;
	size_t m_objSize;
	size_t m_remainBytes;
	void* m_pFirstBlock;
	char* m_pCurrObj;
	void* m_pFreeObj;
};

template <typename T>
T* newElement()
{
	T* ptr = static_cast<T*>(MemoryPool::retrieve(sizeof(T)));
	new(ptr) T();
	return ptr;
}

template <typename T>
void deleteElement(T* obj)
{
	obj->~T();
	MemoryPool::revert(static_cast<void*>(obj), sizeof(T));
}

#endif
memory.cpp 复制代码
#include "memorypool.h"

static MemoryPool memoryPool[FREE_LIST_COUNT];

MemoryPool::MemoryPool()
	: m_blockSize(BLOCK_SIZE)
	, m_objSize(0)
	, m_remainBytes(0)
	, m_pFirstBlock(nullptr)
	, m_pCurrObj(nullptr)
	, m_pFreeObj(nullptr)
{
}

MemoryPool::~MemoryPool()
{
	void* curr = m_pFirstBlock;
	while (curr != nullptr)
	{
		void* next = *(void**)m_pFirstBlock;
		operator delete(curr);
		curr = next;
	}
}

void MemoryPool::init(size_t size)
{
	m_objSize = size;
}

void* MemoryPool::allocate()
{
	void* obj = nullptr;
	if (m_pFreeObj != nullptr)
	{
		obj = m_pFreeObj;
		m_pFreeObj = *(void**)m_pFreeObj;
	}

	else
	{
		if (m_remainBytes < m_objSize)
		{
			m_remainBytes = m_blockSize;
			void* newBlock = operator new(m_blockSize);
			*(void**)newBlock = m_pFirstBlock;
			m_remainBytes -= sizeof(void*);

			m_pFirstBlock = newBlock;
			m_pCurrObj = static_cast<char*>(newBlock) + sizeof(void*);
		}

		obj = m_pCurrObj;
		m_pCurrObj += m_objSize;
		m_remainBytes -= m_objSize;
	}
	return obj;
}

void MemoryPool::deallocate(void* obj)
{
	*(void**)obj = m_pFreeObj;
	m_pFreeObj = obj;
}

void MemoryPool::initMemoryPool()
{
	for (size_t i = 0; i < FREE_LIST_COUNT; i++)
	{
		getFreeList(i).init((i + 1) * BASE_OBJ_SIZE);
	}
}

MemoryPool& MemoryPool::getFreeList(size_t index)
{
	return memoryPool[index];
}

void* MemoryPool::retrieve(size_t size)
{
	if (size > MAX_OBJ_SIZE)
		return operator new(size);

	return getFreeList((size + BASE_OBJ_SIZE - 1) / BASE_OBJ_SIZE - 1).allocate();
}

void MemoryPool::revert(void* obj, size_t size)
{
	if (size > MAX_OBJ_SIZE)	
	{
		operator delete(obj);
		return;
	}
	getFreeList((size + BASE_OBJ_SIZE - 1) / BASE_OBJ_SIZE - 1).deallocate(obj);
}
test.cpp 复制代码
#include "memorypool.h"

#include <iostream>
#include <new>

// 测试用例
class P1
{
    int m_id;
};

class P2
{
    int m_id[500];
};

class P3
{
    int m_id[10];
};

class P4
{
    int m_id[20];
};

// 单轮次申请释放次数
void BenchmarkMemoryPool(size_t ntimes)
{
    size_t total_costtime = 0;
    size_t begin1 = clock();
    try
    {
        for (size_t i = 0; i < ntimes; i++)
        {
            P1* p1 = newElement<P1>();
            deleteElement<P1>(p1);
            P2* p2 = newElement<P2>();
            deleteElement<P2>(p2);
            P3* p3 = newElement<P3>();
            deleteElement<P3>(p3);
            P4* p4 = newElement<P4>();
            deleteElement<P4>(p4);
        }
    }
    catch (const std::bad_alloc& e)
    {
        std::cerr << "Memory allocation failed: ";
        std::cerr << e.what() << std::endl;
    }
    size_t end1 = clock();
    total_costtime += end1 - begin1;
    std::cout << "单轮次申请释放次数: " << ntimes << std::endl;
    std::cout << total_costtime << std::endl;
}

void Benchmark(size_t ntimes)
{
    size_t total_costtime = 0;
    size_t begin1 = clock();
    try
    {
        for (size_t i = 0; i < ntimes; i++)
        {
            P1* p1 = new P1();
            delete p1;
            P2* p2 = new P2();
            delete p2;
            P3* p3 = new P3();
            delete p3;
            P4* p4 = new P4();
            delete p4;
        }
    }
    catch (const std::bad_alloc& e)
    {
        std::cerr << "Memory allocation failed: ";
        std::cerr << e.what() << std::endl;
    }
    size_t end1 = clock();
    total_costtime += end1 - begin1;
    std::cout << "单轮次申请释放次数: " << ntimes << std::endl;
    std::cout << total_costtime << std::endl;
}

int main()
{
    MemoryPool::initMemoryPool();
    BenchmarkMemoryPool(100000);
    Benchmark(100000);
}
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
写bug写bug3 分钟前
Java并发编程:深入理解Java线程状态
java·后端
写bug写bug6 分钟前
Java 中如何优雅地处理 null 值
java·后端
刘_小_二6 分钟前
使用MinIO时出现“Access Denied“错误-小记
后端
喆星时瑜43 分钟前
【IDEA】创建 SpringBoot 项目连接 MySQL
spring boot·后端·mysql·intellij-idea
uhakadotcom1 小时前
Langflow 1.3.0 安全漏洞详解及利用示例,教你如何防范远程代码执行攻击
面试·架构·github
Moonbit1 小时前
「码力全开,论道蓉城」MoonBit Meetup 携技术专家来成都啦!
后端·面试·开源
架构精进之路1 小时前
Deepseek 这么厉害,普通人怎么用好它?
后端·langchain·ai编程
孟意昶1 小时前
大数据面试问答-Kafka/Flink
大数据·面试·kafka
Lafar2 小时前
Dart单线程怎么保证UI运行流畅
前端·面试
uhakadotcom2 小时前
BentoML远程代码执行漏洞(CVE-2025-27520)详解与防护指南
后端·算法·面试