c++内存管理

c++内存分配方式

在C++中,内存分成4个区,他们分别是堆/自由存储区、栈、全局/静态存储区和常量存储区。

:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

堆/自由存储区:就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
PS: 这里将自由存储区和堆放在一起,是因为它们极其相似,这里不探讨它们的异同点,如需知晓,请查看 https://www.cnblogs.com/QG-whz/p/5060894.html

全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

程序员通常考虑的内存为堆、栈内存。其中栈内存只有在极少数情况下才会被考虑到,比如递归函数的深度;而栈内存则经常会被考虑。这两者也是被经常拿来相互比较的。

堆内存和栈内存的区别

在这里插入图片描述

如上图所示是一个unix操作系统的c++进程内存分配,可以看到一个c++进程的内存可以分为(由高到低)命令行参数和环境变量、栈内存、堆内存、未初始化数组段、初始化数据段,代码段。

  1. 堆内存由低到高分配,栈内存由高到低分配。
  2. 栈由系统自动分配,速度快,程序员无法控制,一般来说较为安全;堆内存需要程序员手段申请释放,速度慢,容易产生碎片。
  3. 堆会产生内存碎片,栈则一般不会。
  4. 堆内存大小受限于计算机位数,一般32bit的计算机最大堆内存为4G,64bit的就很大了;栈内存是一块连续的区域,一般来说操作系统就预定好了,一般1M或者2M,不过可以调节。

下面从一段代码看看内存分配的过程(这段代码好多都一样,基本都是拷贝,哈哈,不过确实能说明问题)

int a = 0; //全局初始化区 
char *p1; //全局未初始化区 
main() 
{ 
    int b; //栈 
    char s[] = "abc"; //栈 
    char *p2; //栈 
    char *p3 = "123456"; //123456\0在常量区,p3在栈上。 
    static int c =0; //全局(静态)初始化区 
    p1 = (char *)malloc(10); 
    p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。 
    strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 
}

内存池

既然堆内存管理有这么多的麻烦(内存泄漏、内存碎片、分配效率较慢),许多程序员就想着开发一个专门的内存管理库。

这个内存管理库其实很简单,也就是提前分配一大片内存区域,将该内存区域映射到固定的结构体中,供调用者取用。

本人实现了一个简易的int内存池,该内存池由一个定长int数组和index构成,index的加入是为了便于在释放内存时候查询。代码通用性不强,多线程支持不够好,可以作为一个入门级的学习代码,可以后续改进后增强多进程的性能。

#ifndef TEST_INT_POOL_H
#define TEST_INT_POOL_H

#endif //TEST_INT_POOL_H

#include <memory.h>
#include <algorithm>
#include <map>
#include <list>
#include <mutex>
#include <thread>
#include "constant.h"

using namespace std;

struct Block{
    int index;
    int32_t* value;
};

typedef map<int, Block> BlockVector;

class IntPool{

public:
    IntPool(int block_size, int pre_allocate, int total_allocate);
    ~IntPool();
    Block* get();
    size_t get_block_size();
    int get_allocated();
    int get_avilable();
    void release(Block block);
    int get_used();

private:
    size_t block_size;
    int pre_allocate;
    int allocate;
    int total_allocate;
    int used=0;
    BlockVector block_map;
    list<int> unused_key;

private:
    std::mutex mt;
};
#include <iostream>
#include "int_pool.h"

IntPool::IntPool(int block_size, int pre_allocate, int total_allocate) {

    if(pre_allocate > total_allocate) {
        throw 1;
    }
    this->block_size = block_size;
    this->pre_allocate = pre_allocate;
    this->total_allocate = total_allocate;
    for(int i=0 ; i < this->pre_allocate; i++) {

        Block block;
        block.index = i;
        block.value = new int[block_size];
        unused_key.push_back(i);
        block_map[i] = block;
    }
    allocate = pre_allocate;
}

IntPool::~IntPool() {

    for(int i=0; i<allocate; i++){

        Block b = block_map[i];
        delete[] b.value;
    }
}

Block* IntPool::get() {

    std::lock_guard<std::mutex> lck(mt);
    //如果unused不为空,直接分配一个
    if (unused_key.size() > 0) {
        int key = unused_key.front();
        unused_key.pop_front();
        Block block = block_map[key];
        used++;
        return &block;
    }

    //达到分配定额,则返回nullptr
    if (allocate >= total_allocate){
//        cout << "run out of memory" << endl;
        return nullptr;
    }
    //继续分配内存
    int left = total_allocate - allocate;
    int cur_allocate = left < ALLOCATE_SIZE_PERTIME?left:ALLOCATE_SIZE_PERTIME;
    cout << "reallocate num: " << cur_allocate << " threadid is : " << std::this_thread::get_id()<<endl;
    int i=allocate;
    for( ; i<allocate+cur_allocate-1; i++) {
        Block block;
        block.index = i;
        block.value = new int[block_size];
        unused_key.push_back(i);
        block_map[i] = block;
    }
    allocate = allocate + cur_allocate;
    cout << "current allocate is : " << allocate << endl;
    //留下一个空位返回
    Block block;
    block.index = i;
    block.value = new int[block_size];
    block_map[i] = block;
    used++;
    return &block;
}

void IntPool::release(Block block) {

    std::lock_guard<std::mutex> lck(mt);
    int id = block.index;
    memset(block.value, 0, block_size);
    used--;
    unused_key.push_back(id);
}

size_t IntPool::get_block_size() { return block_size; }

int IntPool::get_allocated() { return allocate; }

int IntPool::get_avilable() { return total_allocate - allocate; }

int IntPool::get_used() { return used; }
#ifndef TEST_CONSTANT_H
#define TEST_CONSTANT_H

#endif //TEST_CONSTANT_H

#define DEFAULT_PRE_BLOCKSIZE 2000
#define DEFAULT_PRE_CAPACITY 100000
#define DEFAULT_MAX_CAPACITY 10000000

#define ALLOCATE_SIZE_PERTIME 100000

github地址:https://github.com/JackandLilac/memory_pool

参看文献

1.https://www.cnblogs.com/findumars/p/5929831.html?utm_source=itdadao&utm_medium=referral
2.https://blog.csdn.net/xjtuse2014/article/details/52302083/
3.https://blog.csdn.net/yangyong0717/article/details/78001609

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值