内存池(一)

本文介绍了内存池的概念、优点(如内存利用率高和性能提升)、整体架构流程,以及如何通过UMemoryPool类实现内存分配和释放。后续会涉及内存块大小调整和多线程优化。
摘要由CSDN通过智能技术生成

概要

一个简单内存池的实现。
内存池是一种内存分配方式。内存池主要由内存单元、内存块和内存池三部分组成。其中,内存单元是实际上使用的内存;内存块由内存块对象和多个大小相等的内存单元组成;内存池是在真正使用内存之前,先申请分配一定数量的、大小相等的内存块留作备用。

内存池的优点
①充分利用内存空间,不会造成太多的资源浪费。
②尽量避免了内存碎片,使得内存分配效率得到提升。
③提高了程序局部性,提升了程序性能。
④比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。
内存池的缺点
①内存池管理(包括分配和回收)困难,效率低。
②容易造成内存空间的浪费。

整体架构流程

<MemoryPool.h>
#pragma once
#include<list>
#include<iostream>
#include <Windows.h>

#define MEMORY_BLOCK_SIZE  1024
#define MEMORY_BLOCK_COUNT 10

class UMemoryPool
{
public:
    UMemoryPool(size_t blockSize, size_t blockCount)
        :blockSize(blockSize),
        blockCount(blockCount),
        freeCount(blockCount)
    {
        // 分配内存池的内存
        pool = new char[blockSize* blockCount];
        ptr = pool;
        //初始化空闲列表
        for (size_t i = 0; i < blockCount; i++)
        {
            freeList.push_back(ptr);
            ptr += blockSize;
        }
    }
    ~UMemoryPool()
    {
        delete []pool;
        freeList.clear();
    }
    // 分配内存块
    void* allocate();
    //释放内存块
    void deallocate(void* ptr);
    //获取内存块剩余数量
    size_t getFreeBlockCount();
private:
    size_t blockSize;       // 每个内存块的大小
    size_t blockCount;      // 内存块的个数
    size_t freeCount;       // 剩余空闲内存块
    char* ptr;
    char* pool;             // 内存池的内存起始地址
    std::list<char*> freeList;;  // 空闲列表,存储可用内存块的索引
};
<MemoryPool.cpp>
#include "UMemoryPool.h"
void* UMemoryPool::allocate()
{
    if (freeList.empty()) {
        throw std::bad_alloc();  // 内存池已满
    }

    char* block = freeList.front();
    freeList.pop_front();
    freeCount--;
    char* alignedBlock = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(block) + sizeof(std::max_align_t) - 1) & ~(sizeof(std::max_align_t) - 1));//偏移量和按位取反进行按位与运算
    return alignedBlock;
}

void UMemoryPool::deallocate(void *ptr) {
    //无效指针
    if (!ptr)
    {
        return;
    }
    char* charPtr = static_cast<char*>(ptr);
    auto it = freeList.begin();
    freeList.push_back(charPtr);
    freeCount++;
}

size_t UMemoryPool::getFreeBlockCount()
{
    return freeCount;
}

技术细节

    size_t blockSize;       // 每个内存块的大小
    size_t blockCount;      // 内存块的个数
    size_t freeCount;       // 剩余空闲内存块
    char* ptr;
    char* pool;             // 内存池的内存起始地址
    std::list<char*> freeList;;  // 空闲列表,存储可用内存块的索引

1、内存池搭建第一步,先申请一块大内存,我们称之为页(page),页里由众多内存块(block)组成。
通过构造函数,我们确定内存池的大小,并声明一个链表freeList对内存块进行管理。

UMemoryPool(size_t blockSize, size_t blockCount)
        :blockSize(blockSize),
        blockCount(blockCount),
        freeCount(blockCount)
    {
        // 分配内存池的内存
        pool = new char[blockSize* blockCount];
        ptr = pool;
        //初始化空闲列表
        for (size_t i = 0; i < blockCount; i++)
        {
            freeList.push_back(ptr);
            ptr += blockSize;
        }
    }

2、申请内存接口实现
检查freelist是否为空,为空就代表没有空闲内存块,获取第一块空闲内存块,字节对齐后,返回给用户,并把这块内存地址从freelist中弹出。
字节对齐的作用
①减少对内存的读取次数,提高读取效率。
②减少内存空间的浪费,节省存储空间。
③保证数据在内存中的连续存储,减少内存碎片的产生。
④保证数据在不同的计算机上都可以正确地读取和处理,增加数据的可移植性。

void* UMemoryPool::allocate()
{
    if (freeList.empty()) {
        throw std::bad_alloc();  // 内存池已满
    }

    char* block = freeList.front();
    freeList.pop_front();
    freeCount--;
    char* alignedBlock = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(block) + sizeof(std::max_align_t) - 1) & ~(sizeof(std::max_align_t) - 1));//偏移量和按位取反进行按位与运算
    return alignedBlock;
}

3、释放内存接口实现:
释放内存,就是表示这块内存已经不再使用,进入空闲状态。将这块内存地址重新加入freelist中,待下回再次使用。

void UMemoryPool::deallocate(void *ptr) {
    //无效指针
    if (!ptr)
    {
        return;
    }
    char* charPtr = static_cast<char*>(ptr);
    freeList.push_back(charPtr);
    freeCount++;
}

4、内存池的使用

#include "UMemoryPool.h"


void main()
{

    UMemoryPool pool(MEMORY_BLOCK_SIZE, MEMORY_BLOCK_COUNT);  // 创建一个内存池,每个块大小为1024字节,总共10个块

    for (size_t i = 0; i < 100; i++)
    {
        void* ptr1 = pool.allocate();
        void* ptr2 = pool.allocate();
        std::cout << "Allocate after: " << pool.getFreeBlockCount() << std::endl;
        // 使用ptr1和ptr2...
        pool.deallocate(ptr1);
        pool.deallocate(ptr2);
        std::cout << "deallocate After: " << pool.getFreeBlockCount() << std::endl;
        Sleep(10);
    }

}

小结

这是一个简单的内存池实现,还会有内存块大小调整,碎片整理,多线程环境使用等等功能,在后续优化中慢慢增加。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值