如何用C++实现简单的内存池

开发 前端
内存池(Memory Pool)是计算机编程中一种重要的内存管理技术,它预先分配一块较大的内存区域,并将其划分为多个大小相等的内存块。这种技术旨在减少因频繁申请和释放小块内存而引发的性能开销。

内存池(Memory Pool)是计算机编程中一种重要的内存管理技术,它预先分配一块较大的内存区域,并将其划分为多个大小相等的内存块。这种技术旨在减少因频繁申请和释放小块内存而引发的性能开销。下面,我们将结合代码,一步步讲解如何实现一个简单的内存池,并分析其工作原理。

一、内存池的基本概念

内存池是一种用于动态内存分配的技术,其核心思想是空间换时间。通过预先分配一大块内存,并将其划分为多个小块,内存池能够快速地为程序提供所需的内存,而无需每次都向操作系统申请。这样可以大大减少内存分配和释放的开销,提高程序的运行效率。

二、内存池的实现步骤

1. 定义内存池类

首先,我们定义一个名为AdvancedMemoryPool的模板类,它接受一个类型参数T和一个默认大小为100的整数参数PoolSize。这个类将用于管理内存池的分配和回收。

template <typename T, size_t PoolSize = 100>
class AdvancedMemoryPool {
    // ...
};

2. 初始化内存池

在类的构造函数中,我们调用expandPool函数来初始化内存池。这个函数将分配一块大小为PoolSize * sizeof(T)的内存,并将其划分为PoolSize个大小为sizeof(T)的内存块。这些内存块的地址被添加到freeChunks_列表中,表示它们是空闲的,可以被分配。

AdvancedMemoryPool() {
    expandPool();
}

private:
void expandPool() {
    char* newBlock = new char[sizeof(T) * PoolSize];
    for (size_t i = 0; i < PoolSize; ++i) {
        freeChunks_.push_back(reinterpret_cast<T*>(newBlock + i * sizeof(T)));
    }
    pool_.push_back(newBlock);
}

3. 分配内存块

alloc函数用于从内存池中分配一个空闲的内存块。它首先检查freeChunks_列表是否为空。如果为空,则调用expandPool函数来扩展内存池。然后,它从freeChunks_列表中取出一个空闲的内存块,并将其从列表中移除。最后,返回这个内存块的地址。

T* alloc() {
    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全
    if (freeChunks_.empty()) {
        expandPool();
    }

    T* ptr = freeChunks_.front();
    freeChunks_.pop_front();
    return ptr;
}

这里使用了std::lock_guard来确保在多线程环境下的线程安全。当多个线程同时尝试分配内存时,std::mutex会确保同一时间只有一个线程能够访问内存池。

4. 回收内存块

dealloc函数用于回收一个之前分配的内存块。它接受一个指向要回收的内存块的指针,并将这个指针添加到freeChunks_列表中,表示这个内存块现在是空闲的,可以被再次分配。

void dealloc(T* ptr) {
    assert(ptr != nullptr); // 确保传入的指针不为空
    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全
    freeChunks_.push_back(ptr);
}

同样,这里也使用了std::lock_guard来确保线程安全。

5. 查询内存池状态

我们还提供了两个函数getFreeChunksCount和getUsedChunksCount来查询内存池的状态。这两个函数分别返回空闲和已使用的内存块数量。

size_t getFreeChunksCount() const {
    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全
    return freeChunks_.size();
}

size_t getUsedChunksCount() const {
    return PoolSize - getFreeChunksCount();
}

三、使用内存池

在主函数中,我们创建了一个AdvancedMemoryPool对象,并使用它来分配和回收内存块。通过调用alloc函数,我们可以从内存池中获取一个空闲的内存块,并使用它来存储数据。当我们不再需要这个内存块时,可以调用dealloc函数将其回收回内存池。

四、完整代码

#include <iostream>  
#include <list>  
#include <mutex>  
#include <cassert>  
#include <cstdlib>  
  
template <typename T, size_t PoolSize = 100>  
class AdvancedMemoryPool {  
public:  
    AdvancedMemoryPool() {  
        expandPool();  
    }  
  
    ~AdvancedMemoryPool() {  
        std::lock_guard<std::mutex> lock(mutex_);  
        for (auto& chunk : pool_) {  
            delete[] reinterpret_cast<char*>(chunk);  
        }  
    }  
  
    T* alloc() {  
        std::lock_guard<std::mutex> lock(mutex_);  
        if (freeChunks_.empty()) {  
            expandPool();  
        }  
  
        T* ptr = freeChunks_.front();  
        freeChunks_.pop_front();  
        return ptr;  
    }  
  
    void dealloc(T* ptr) {  
        assert(ptr != nullptr);  
        std::lock_guard<std::mutex> lock(mutex_);  
        freeChunks_.push_back(ptr);  
    }  
  
    size_t getFreeChunksCount() const {  
        std::lock_guard<std::mutex> lock(mutex_);  
        return freeChunks_.size();  
    }  
  
    size_t getUsedChunksCount() const {  
        return PoolSize - getFreeChunksCount();  
    }  
  
private:  
    void expandPool() {  
        char* newBlock = new char[sizeof(T) * PoolSize];  
        for (size_t i = 0; i < PoolSize; ++i) {  
            freeChunks_.push_back(reinterpret_cast<T*>(newBlock + i * sizeof(T)));  
        }  
        pool_.push_back(newBlock);  
    }  
  
    mutable std::mutex mutex_;  
    std::list<T*> freeChunks_;  
    std::list<char*> pool_;  
};  
  
// 使用示例  
struct ComplexObject {  
    int data[100];  
    // 假设这是一个复杂的对象,需要动态分配  
};  
  
int main() {  
    AdvancedMemoryPool<ComplexObject> pool;  
  
    ComplexObject* obj1 = pool.alloc();  
    ComplexObject* obj2 = pool.alloc();  
  
    std::cout << "Free chunks: " << pool.getFreeChunksCount() << std::endl;  
    std::cout << "Used chunks: " << pool.getUsedChunksCount() << std::endl;  
  
    pool.dealloc(obj1);  
    pool.dealloc(obj2);  
  
    std::cout << "Free chunks after deallocation: " << pool.getFreeChunksCount() << std::endl;  
    std::cout << "Used chunks after deallocation: " << pool.getUsedChunksCount() << std::endl;  
  
    return 0;  
}
责任编辑:华轩 来源: 鲨鱼编程
相关推荐

2020-03-05 15:34:16

线程池C语言局域网

2021-04-04 08:00:39

C++编程语言软件开发

2010-01-22 13:31:58

C++标准库

2010-01-13 18:44:03

C++编译

2011-07-20 14:33:19

C++IO

2014-06-04 13:19:29

C++ndk安卓开发

2010-01-25 13:43:09

C++算术编码

2023-10-26 11:03:50

C语言宏定义

2015-11-30 11:14:59

C++对象池自动回收

2019-09-29 00:25:11

CC++内存泄漏

2011-04-11 09:47:50

C++内存管理

2024-01-15 06:01:36

C++数组

2010-01-26 15:51:06

C++变量

2011-06-16 09:28:02

C++内存泄漏

2009-08-19 09:57:01

C++ RAII

2023-11-17 11:40:51

C++内存

2012-02-01 11:20:23

Java线程

2009-08-19 10:09:21

C#和C++

2010-01-18 17:48:46

C++类对象

2010-01-25 18:15:52

点赞
收藏

51CTO技术栈公众号