c++内存管理
c++内存分配方式
在C++中,内存分成4个区,他们分别是堆/自由存储区、栈、全局/静态存储区和常量存储区。
栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆/自由存储区:就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
PS: 这里将自由存储区和堆放在一起,是因为它们极其相似,这里不探讨它们的异同点,如需知晓,请查看 https://www.cnblogs.com/QG-whz/p/5060894.html
全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
程序员通常考虑的内存为堆、栈内存。其中栈内存只有在极少数情况下才会被考虑到,比如递归函数的深度;而栈内存则经常会被考虑。这两者也是被经常拿来相互比较的。
堆内存和栈内存的区别
如上图所示是一个unix操作系统的c++进程内存分配,可以看到一个c++进程的内存可以分为(由高到低)命令行参数和环境变量、栈内存、堆内存、未初始化数组段、初始化数据段,代码段。
- 堆内存由低到高分配,栈内存由高到低分配。
- 栈由系统自动分配,速度快,程序员无法控制,一般来说较为安全;堆内存需要程序员手段申请释放,速度慢,容易产生碎片。
- 堆会产生内存碎片,栈则一般不会。
- 堆内存大小受限于计算机位数,一般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 █
}
//达到分配定额,则返回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 █
}
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.****.net/xjtuse2014/article/details/52302083/
3.https://blog.****.net/yangyong0717/article/details/78001609