内存使用技巧及内存池实现(二)
2015-08-16 16:45
239 查看
转载地址:http://blog.csdn.net/gugemichael/article/details/7547143
上一章节,提到了内存池的使用。其实内存池的作用看名字也能猜到,"池"意味着资源是同一管理和创建释放的,就像数据库的连接池、系统的线程池。主要就是为了避免创建、销毁资源的代价。c标准的malloc/free会造成大量的内存碎片以至于影响效率,所以“内存池”的技术某种程度上避免了这种消耗和影响。
本人觉得实现的内存池可以分为3级:
1、初级的简单内存池实现:解决malloc小空间的碎片化,托管回收。适用于函数或类,不跨线程
2、高级的内存池:通过块链式的方式长期托管内存,可以半自动的释放内存,并可以动态规划内存的块存储(类似linux内核BuddySystem)。
3、可以托管内存和相关资源(文件句柄、数据库连接)的池 : 将和该块内存相关联的内存、资源整合,统一托管!全局托管资源。
本文会实现并讲解1、2中的内存池实现方式。第3种时间和技术有限,大家可以自行写一写,或者用C++的RAII技术和STL中的实现来用。
简单的内存池实现,核心思想就是想申请一块大内存(mb级别,并且为512KB的整数倍,好处是和linux内存管理配套,数字根据应用不同可以改),这样做可能有一定的浪费,不过试想一下,如果只是申请几十个Byte,根本用不到内存池。用到了内存池肯定空间不会太小。然后从这块大内存上用游标控制分配,alloc一块内存指针就移动固定位数,最后统一释放。这样,在操作系统看来,就总是去申请很大一块内存,并且造成碎片的几率很低,速度也快。
![](http://my.csdn.net/uploads/201205/08/1336472362_4790.jpg)
这种实现方式不会让用户去free,因为free了也没用,池子并不会服用。但是这块大内存的生命周期不会很长,所以一般场景下不影响。下一小节会介绍"高级"一点的实现的方式,通过动态的拆分和合并来管理不同大小的内存。
废话不多说,直接上代码:
[cpp]
view plaincopyprint?
typedef struct _mempool simple_mempool;
struct _mempool {
uint32_t size; // memory pool total size (512KB * n)
void *raw_area;
void *cursor; // indicate the current position of pool
};
内存池结构体句柄,保存大小、游标,和原始malloc指针。
[cpp]
view plaincopyprint?
/**
* Don't allocate more than 512M space, because this mempool
* just implement simple way of pool, it don't free anything
* util call simple_mempool_destroy(), this feature is based
* on JUST USE it in an funtion or in one class
*/
void* simple_mempool_create(uint32_t size)
{
if (size==0 || size>=1024*512)
return NULL;
// align of 4 byte
// size += size % 4;
simple_mempool *pool = (simple_mempool*)calloc(1,sizeof(simple_mempool));
pool->size = CHUNK_SIZE*size;
pool->raw_area = calloc(1,1024*size);
pool->cursor = pool->raw_area;
return pool;
}
创建内存池,如果大于512M就忽略,建议使用高级内存池。
[cpp]
view plaincopyprint?
uint8_t simple_mempool_could_allocate(simple_mempool* pool, uint32_t n)
{
// cursor will out of the end
if ((pool->cursor-pool->raw_area)+n > pool->size)
return 0;
else
return 1;
}
void* simple_mempool_allocate(simple_mempool* pool, uint32_t n)
{
// no space here
if (NULL==pool || NULL==pool->raw_area || !simple_mempool_could_allocate(pool,n))
return NULL;
void* ret = pool->cursor;
// move the cursor
pool->cursor = (void*)((char*)pool->cursor + n);
return ret;
}
实际分配函数,只是挪动了一下cursor指针而已。
[cpp]
view plaincopyprint?
uint32_t simple_mempool_left(simple_mempool *pool)
{
if (NULL == pool)
return -1;
else return pool->size - (pool->cursor - pool->raw_area);
}
查看剩余量,此处pool->size / pool->cursor - pool->raw_area等是无符号整型,虽然没做边界校验,但是allocate函数保证了cursor不会超过size。
[cpp]
view plaincopyprint?
void simple_mempool_destroy(simple_mempool* pool)
{
free(pool->raw_area);
pool->cursor = pool->raw_area = NULL;
pool->size = 0;
}
释放内存池,pool句柄可复用。
下面是ut单侧的代码,分配完了就destroy并退出 :
[cpp]
view plaincopyprint?
#define ut_main main
int ut_main()
{
simple_mempool *pool = simple_mempool_create(1);
while(1) {
long long *tmp = simple_mempool_allocate(pool,sizeof(long long));
if (NULL == tmp) {
printf("no space in mempool , destroy it !!!");
simple_mempool_destroy(pool);
break;
}
}
return 0;
}
周末我会把第2种实现的比较良好的内存池的实现方式贴上来,大家一起讨论。
上一章节,提到了内存池的使用。其实内存池的作用看名字也能猜到,"池"意味着资源是同一管理和创建释放的,就像数据库的连接池、系统的线程池。主要就是为了避免创建、销毁资源的代价。c标准的malloc/free会造成大量的内存碎片以至于影响效率,所以“内存池”的技术某种程度上避免了这种消耗和影响。
本人觉得实现的内存池可以分为3级:
1、初级的简单内存池实现:解决malloc小空间的碎片化,托管回收。适用于函数或类,不跨线程
2、高级的内存池:通过块链式的方式长期托管内存,可以半自动的释放内存,并可以动态规划内存的块存储(类似linux内核BuddySystem)。
3、可以托管内存和相关资源(文件句柄、数据库连接)的池 : 将和该块内存相关联的内存、资源整合,统一托管!全局托管资源。
本文会实现并讲解1、2中的内存池实现方式。第3种时间和技术有限,大家可以自行写一写,或者用C++的RAII技术和STL中的实现来用。
简单的内存池实现,核心思想就是想申请一块大内存(mb级别,并且为512KB的整数倍,好处是和linux内存管理配套,数字根据应用不同可以改),这样做可能有一定的浪费,不过试想一下,如果只是申请几十个Byte,根本用不到内存池。用到了内存池肯定空间不会太小。然后从这块大内存上用游标控制分配,alloc一块内存指针就移动固定位数,最后统一释放。这样,在操作系统看来,就总是去申请很大一块内存,并且造成碎片的几率很低,速度也快。
![](http://my.csdn.net/uploads/201205/08/1336472362_4790.jpg)
这种实现方式不会让用户去free,因为free了也没用,池子并不会服用。但是这块大内存的生命周期不会很长,所以一般场景下不影响。下一小节会介绍"高级"一点的实现的方式,通过动态的拆分和合并来管理不同大小的内存。
废话不多说,直接上代码:
[cpp]
view plaincopyprint?
typedef struct _mempool simple_mempool;
struct _mempool {
uint32_t size; // memory pool total size (512KB * n)
void *raw_area;
void *cursor; // indicate the current position of pool
};
内存池结构体句柄,保存大小、游标,和原始malloc指针。
[cpp]
view plaincopyprint?
/**
* Don't allocate more than 512M space, because this mempool
* just implement simple way of pool, it don't free anything
* util call simple_mempool_destroy(), this feature is based
* on JUST USE it in an funtion or in one class
*/
void* simple_mempool_create(uint32_t size)
{
if (size==0 || size>=1024*512)
return NULL;
// align of 4 byte
// size += size % 4;
simple_mempool *pool = (simple_mempool*)calloc(1,sizeof(simple_mempool));
pool->size = CHUNK_SIZE*size;
pool->raw_area = calloc(1,1024*size);
pool->cursor = pool->raw_area;
return pool;
}
创建内存池,如果大于512M就忽略,建议使用高级内存池。
[cpp]
view plaincopyprint?
uint8_t simple_mempool_could_allocate(simple_mempool* pool, uint32_t n)
{
// cursor will out of the end
if ((pool->cursor-pool->raw_area)+n > pool->size)
return 0;
else
return 1;
}
void* simple_mempool_allocate(simple_mempool* pool, uint32_t n)
{
// no space here
if (NULL==pool || NULL==pool->raw_area || !simple_mempool_could_allocate(pool,n))
return NULL;
void* ret = pool->cursor;
// move the cursor
pool->cursor = (void*)((char*)pool->cursor + n);
return ret;
}
实际分配函数,只是挪动了一下cursor指针而已。
[cpp]
view plaincopyprint?
uint32_t simple_mempool_left(simple_mempool *pool)
{
if (NULL == pool)
return -1;
else return pool->size - (pool->cursor - pool->raw_area);
}
查看剩余量,此处pool->size / pool->cursor - pool->raw_area等是无符号整型,虽然没做边界校验,但是allocate函数保证了cursor不会超过size。
[cpp]
view plaincopyprint?
void simple_mempool_destroy(simple_mempool* pool)
{
free(pool->raw_area);
pool->cursor = pool->raw_area = NULL;
pool->size = 0;
}
释放内存池,pool句柄可复用。
下面是ut单侧的代码,分配完了就destroy并退出 :
[cpp]
view plaincopyprint?
#define ut_main main
int ut_main()
{
simple_mempool *pool = simple_mempool_create(1);
while(1) {
long long *tmp = simple_mempool_allocate(pool,sizeof(long long));
if (NULL == tmp) {
printf("no space in mempool , destroy it !!!");
simple_mempool_destroy(pool);
break;
}
}
return 0;
}
周末我会把第2种实现的比较良好的内存池的实现方式贴上来,大家一起讨论。
相关文章推荐
- 排序算法
- Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)
- MySQL外键约束
- 第一泰泽(Tizen)智能手机发布在俄罗斯
- 内存使用技巧及内存池实现(一)
- 毕业小记
- C++: 继承与派生
- 存储过程循环添加数据到数据库中
- BestCoder 1st Anniversary ($) 1001 1002 1003
- BestCoder#51
- usaco Healthy Holsteins individual report
- 使用mybatis-gen生成sql
- 远程连接mongodb时,27017端口连接不上的解决办法
- HDU 2222 (AC自动机模板题)
- 文件锁FileLock
- 断其一指------异步任务(AsyncTask)
- 大牛们的博客收集
- css滤镜实现页面灰色黑白色效果代码
- Spring Web Flow 学习笔记(2)-流程的组件
- 销售高手们都是如何逼单的?