c++ 快速内存池

/*

  • 编写一个内存池,在运行期间不进行动态内存分配

  • 为了实现快速的内存分配,通常一个内存池分配器使用预定义大小的块。
  • 这个想法类似于隔离列表,但是块的确定更加快速。
  • 池分配器使用块(池)和每个块中的小块的概念进行操作。
  • 每个块都有预定的大小,并对对象头进行编码,其中存储着元信息。
  • 为分配器或收集器的目的所需。由于大小是预定义的,我们不需要在头中存储
  • 它在头中,而只能保持对下一个对象的引用。
  • 特点。
    • 参数化的池大小
  • 应考虑内存对齐
  • 在初始化过程中进行块分配(或者在编译过程中更好)。
  • 块的内存应该已经被预分配了
  • allocate()方法向内存池索取一个空闲块
  • free()方法将内存块放回内存池中
  • getFreeSlots()方法用于跟踪内存池的使用情况
    */
#include <iostream>
#include <cassert>

template<typename T, const size_t NumberOfChunks>
class MemoryPool
{

public:
    MemoryPool()
    {
        len=NumberOfChunks;
        data=new T*[len];
        for(size_t i=0; i<len; i++)
        {
            data[i]=nullptr;//还没有被占用
        }
    }

    virtual ~MemoryPool()
    {
        for(size_t i=0; i<len; i++)
        {
            if(data[i]!=nullptr)
            {
                delete data[i];
            }
        }
        delete[] data;
    }


    template<typename... Args>
    T* allocate(Args&&... args)
    {

        int idx[]= {args...};
        if(data[idx[0]]!=nullptr)
        {
            //已经被占用了
            return nullptr;
        }
        data[idx[0]]=new T(idx[0]);
        return data[idx[0]];
    }

    void free(T* element)
    {
        for(size_t i=0; i<len; i++)
        {
            if(data[i]==element)
            {
                delete data[i];
                data[i]=nullptr;
            }
        }
    }

    int getFreeSlots() const
    {
        int ret=0;
        for(size_t i=0; i<len; i++)
        {
            if(data[i]==nullptr)
            {
                ret++;
            }
        }
        return ret;
    }

private:
    size_t len=0;
    T** data=nullptr;
};

/*
 * Dummy object to be used later
 */
class MyClass
{
public:
    explicit MyClass(int i=0)
    {
        std::cout << "MyClass ctor: " << i << std::endl;
        _my_value.my_int = i;
    }

    ~MyClass()
    {
        std::cout << "MyClass dtor: " << _my_value.my_int << std::endl;
    }

    int foo()
    {
        std::cout << "MyClass foo(): " << _my_value.my_int << std::endl;
        return _my_value.my_int;
    }

private:
    typedef struct __attribute__ ((__packed__))
    {
        int my_int = 0;
        uint8_t my_uint8;
    } MyValueType;
    MyValueType _my_value;
};


int main()
{

    static constexpr int PoolSize = 10;
    MemoryPool<MyClass, PoolSize> MyPool;

    MyClass* data[PoolSize];
    for(int idx=0; idx<PoolSize-1; idx++)
    {
        data[idx] = MyPool.allocate(idx);
        if (data[idx] != nullptr)
        {
            const auto ret = data[idx]->foo();
            assert(ret == idx);
        }
        else
        {
            if(idx < PoolSize )
            {
                assert(false);
            }
            std::cerr << "Unable to get valid memory from Pool" << std::endl;
        }
        std::cout << "Available Chunks: " << MyPool.getFreeSlots() << std::endl;
    }

    for(int idx=0; idx<PoolSize-1; idx++)
    {
        MyPool.free(data[idx]);
        std::cout << "Available Chunks: " << MyPool.getFreeSlots() << std::endl;
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 写一个高效,线程安全的内存池,有几种方法: 1. 使用互斥锁保护内存池的访问。这样,每次访问内存池时都会使用互斥锁来保证线程安全。但是这样会影响性能,因为获取锁和释放锁都会消耗时间。 2. 使用原子操作来保证线程安全。原子操作是指在一条指令内完成的操作,无法被中断,因此可以保证线程安全。但是原子操作的执行速度要比互斥锁慢,因此在高并发的情况下可能会对性能产生负面影响。 3. 使用分离的内存池。在这种情况下,每个线程都有自己的内存池,因此在不同的线程之间不存在竞争。这样可以大大提高内存池的访问效率,但是同时也增加了内存的消耗。 4. 使用双缓冲池。在这种情况下,有两个内存池,一个用于读,一个用于写。这样,在写的时候,读的线程可以继续使用另一个内存池,从而避免了锁的使用,提高了效率。但是这种方法也有缺点,即需要额外的空间来存储双缓冲池, ### 回答2: C语言内存池是一种用于管理内存分配和释放的技术,可以提高程序的效率和性能。一个高效、线程安全、快速访问的C内存池应该具备以下特点: 1. 采用链表结构:内存池应该使用链表结构来管理空闲内存块,这样可以快速地分配和释放内存。 2. 预分配内存内存池应该在初始化时预分配一定数量的内存块,并将它们加入到空闲列表中。在需要分配内存时,只需要从空闲列表中取出一个内存块即可,这样可以大大减少内存分配的时间。 3. 固定大小的内存块:为了提高内存分配的效率,内存池应该使用固定大小的内存块。这样不同大小的内存块可以互相复用,减少内存碎片的产生。 4. 按需分配内存内存池应该根据实际需求动态分配内存。当内存池中的内存块被分配完时,可以根据需要动态增加内存块的数量,以满足更大的内存需求。 5. 线程安全:内存池应该支持多线程并发访问,保证在多线程环境下的正确性和一致性。可以通过使用互斥锁或信号量来解决线程安全问题。 6. 使用效率和性能:内存池应该尽可能地减少内存分配和释放的次数,以提高程序的效率和性能。可以使用算法来优化内存分配和释放的时间复杂度。 总之,一个高效、线程安全、快速访问的C内存池应该是基于链表结构的,采用预分配内存、固定大小的内存块和按需分配内存的策略。同时,它应该通过使用互斥锁或信号量来实现线程安全,并且应该尽量减少内存分配和释放的次数,以提高程序的效率和性能。 ### 回答3: 为了创建一个高效、线程安全和快速访问的C内存池,我将采用以下设计: 1. 内存池的基本结构:内存池将使用一个动态分配的内存块来存储分配的内存。这个内存块可以根据需求进行扩展或收缩。内存池中的内存单元将使用一个位图来表示其使用情况。 2. 线程安全性:为了保证线程安全性,我们将使用互斥锁(mutex)来防止多个线程同时访问内存池的分配和释放操作。每个线程在进行分配或释放操作时,需要先获取互斥锁。此外,我们还将使用条件变量(condition variable)来管理内存池的空闲内存单元和正在等待空闲内存单元的线程。 3. 内存分配算法:我们将使用分离空闲链表算法(segregated free list algorithm)来管理内存池中的空闲内存单元。这个算法将内存块划分为多个等大小的链表,每个链表存储相同大小的空闲内存单元。当需要分配内存时,我们首先搜索适合大小的链表,如果链表为空,则将内存块扩展,并将新的内存单元添加到相应的链表中。 4. 内存释放和重用:当释放一个内存单元时,我们将检查其相邻的内存单元是否也是空闲的,如果是,则将它们合并为一个更大的内存单元,并重新添加到相应大小的链表中。这样可以减少内存碎片的发生,并提供更高效的内存重用。 总结起来,这个高效、线程安全和快速访问的C内存池将使用动态内存块、位图、互斥锁和条件变量等技术来管理分配和释放内存。它还将使用分离空闲链表算法来有效地管理空闲内存单元,并通过合并相邻的空闲内存单元来减少内存碎片。这种设计可以提供高性能的内存分配和释放操作,同时实现线程安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清欢_小铭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值