http://my.youkuaiyun.com/cyebo/code/detail/37135
在学习内存池的过程中可谓云游太虚。一般都是针对标准内存池再次实现。大部分以链表的形式讨论。诚然最正宗也最准确,但是相对比较晦涩,本文是针对刚刚接触内存池的同学写的。大大减少了对内存池整体认识的难度。
内存池:
如果程序中涉及频繁申请释放内存,并且每次使用的内存并不是很大,这时候应该考虑内存池。
内存池可以有有效的避免内存碎片的产生。
内存池的框架:
class
MemPool{
public
:
MemPool(){初始化分配N个小的内存块}
~MemPool(){真正删除整个分配了的内存空间}
void
*
getmem(){获取内存(块)}
void
freemem(){释放内存到内存池中,这里并不是真正的释放掉内存,只是回收再利用;}
private
:
struct
LinkBlock
* p;
//把很多小内存块关联起来的结构,大部分写成链表的形式
mem_block*
m_block;
//一个小的内存块。
};
工作机制:
事先分配出一大块内存,再把这一大块分成很多小块。当程序中需要申请内存时就拿出一小块来用。用完了就把这一小块放回大块中(注意:这个小块内存并没释放掉!),只要不是一下用掉了所有一大块内存,无论多少次申请内存都是重复利用这些小的内存块。知道程序结束真正释放掉整片内存。
所以用内存池可以把大量的内存申请控制在可计算的范围内。内存碎片少。比如:如果用系统的
new
或者
malloc
申请10000次内存,可能要10000的小的内存空间,但是使用内存池只需申请100块空间,循环利用100次而已。作用显而易见!
为了让程序简单明了使用STL标准库的vector来充当小内存块的管理器。
vector<
char
*>
vec; 这样每次申请的是vec的一个迭代器的空间。
代码非原创,稍稍做了改动而已。
========================================================================
MemPool.h
#ifndef
_MEM_POOL_H
#define
_MEM_POOL_H
#include
<vector>
#include
<iostream>
using
namespace
std;
/*
在内存池中分配固定大小的内存块
目的是加速内存分配速度,并且减少因重复分配相同
*/
class
CMemPool
{
public
:
//创建大小为blockSize的内存块,内存池数目为预分配的数目preAlloc
CMemPool(
int
blockSize,
int
preAlloc
= 0,
int
maxAlloc
= 0);
~CMemPool();
//获取一个内存块。如果内存池中没有足够的内存块,则会自动分配新的内存块
//如果分配的内存块数目达到了最大值,则会返回一个异常
void
*
Get();
//释放当前内存块,将其插入内存池
void
Release(
void
*
ptr);
//返回内存块大小
int
BlockSize()
const
;
//返回内存池中内存块数目
int
Allocated()
const
;
//返回内存池中可用的内存块数目
int
Available()
const
;
private
:
CMemPool();
CMemPool(
const
CMemPool&);
CMemPool&
operator = (
const
CMemPool&);
enum
{
BLOCK_RESERVE
= 128
};
typedef
std::vector<
char
*>
BlockVec;
int
m_blockSize;
int
m_maxAlloc;
int
m_allocated;
BlockVec
m_blocks;
};
inline
int
CMemPool::BlockSize()
const
{
return
m_blockSize;
}
inline
int
CMemPool::Allocated()
const
{
return
m_allocated;
}
inline
int
CMemPool::Available()
const
{
return
(
int
)
m_blocks.size();
}
#endif
=========================================================
MemPool.cpp
#include
"MemPool.h"
CMemPool::CMemPool(
int
blockSize,
int
preAlloc,
int
maxAlloc):
m_blockSize(blockSize),
m_maxAlloc(maxAlloc),
m_allocated(preAlloc)
{
if
(
preAlloc < 0 || maxAlloc == 0 || maxAlloc < preAlloc )
{
cout<<
"CMemPool::CMemPool
parameter error."
<<endl;
}
int
r
= BLOCK_RESERVE;
if
(preAlloc
> r)
r
= preAlloc;
if
(maxAlloc
> 0 && maxAlloc < r)
r
= maxAlloc;
m_blocks.reserve(r);
for
(
int
i
= 0; i < preAlloc; ++i)
{
m_blocks.push_back(
new
char
[m_blockSize]);
}
}
CMemPool::~CMemPool()
{
for
(BlockVec::iterator
it = m_blocks.begin(); it != m_blocks.end(); ++it)
{
delete
[]
*it;
}
}
void
*
CMemPool::Get()
{
if
(m_blocks.empty())
{
if
(m_maxAlloc
== 0 || m_allocated < m_maxAlloc)
{
++m_allocated;
return
new
char
[m_blockSize];
}
else
{
cout<<
"CMemPool::get
CMemPool exhausted."
<<endl;
return
(
void
*)NULL;
}
}
else
{
char
*
ptr = m_blocks.back();
m_blocks.pop_back();
return
ptr;
}
}
void
CMemPool::Release(
void
*
ptr)
{
memset
(ptr,0,
sizeof
(
char
)*m_blockSize);
//内存回收回来以后并没销毁,原数据仍在,所以应该清空
m_blocks.push_back(
reinterpret_cast
<
char
*>(ptr));
}
=========
main.h
#include
"stdafx.h"
#include
"MemPool.h"
#include
<string.h>
int
main(
int
argc,
char
*
argv[])
{
CMemPool
*m_cache =
new
CMemPool(50,0,10);
char
*
src_date=
"abcdefg"
;
char
*p1=(
char
*)(m_cache->Get());
char
*p2=(
char
*)(m_cache->Get());
int
*p3=(
int
*)(m_cache->Get());
strcpy
(p1,src_date);
strcpy
(p2,src_date);
p3[0]=9;p3[1]=25;
m_cache->Release(p1);
m_cache->Release(p2);
m_cache->Release(p3);
//把MemPool.cpp中void
CMemPool::Release(void* ptr) 的
//memset(ptr,0,sizeof(char)*m_blockSize);注释掉可以验证每次内存回收以后是重复利用而非销毁
cout<<*(
int
*)(m_cache->Get())<<endl;
cout<<(
char
*)(m_cache->Get())<<endl;
cout<<(
char
*)(m_cache->Get())<<endl;
delete
m_cache;
return
0;
}
完毕!
当然这只是探究内存池而已,更高级的比如线程安全,内存扩容,模板等等,仍需解决。
但是相信想初窥内存池门径应该还是有帮助的!
http://my.youkuaiyun.com/cyebo/code/detail/37135
在学习内存池的过程中可谓云游太虚。一般都是针对标准内存池再次实现。大部分以链表的形式讨论。诚然最正宗也最准确,但是相对比较晦涩,本文是针对刚刚接触内存池的同学写的。大大减少了对内存池整体认识的难度。
内存池:
如果程序中涉及频繁申请释放内存,并且每次使用的内存并不是很大,这时候应该考虑内存池。
内存池可以有有效的避免内存碎片的产生。
内存池的框架:
class
MemPool{
public
:
MemPool(){初始化分配N个小的内存块}
~MemPool(){真正删除整个分配了的内存空间}
void
*
getmem(){获取内存(块)}
void
freemem(){释放内存到内存池中,这里并不是真正的释放掉内存,只是回收再利用;}
private
:
struct
LinkBlock
* p;
//把很多小内存块关联起来的结构,大部分写成链表的形式
mem_block*
m_block;
//一个小的内存块。
};
工作机制:
事先分配出一大块内存,再把这一大块分成很多小块。当程序中需要申请内存时就拿出一小块来用。用完了就把这一小块放回大块中(注意:这个小块内存并没释放掉!),只要不是一下用掉了所有一大块内存,无论多少次申请内存都是重复利用这些小的内存块。知道程序结束真正释放掉整片内存。
所以用内存池可以把大量的内存申请控制在可计算的范围内。内存碎片少。比如:如果用系统的
new
或者
malloc
申请10000次内存,可能要10000的小的内存空间,但是使用内存池只需申请100块空间,循环利用100次而已。作用显而易见!
为了让程序简单明了使用STL标准库的vector来充当小内存块的管理器。
vector<
char
*>
vec; 这样每次申请的是vec的一个迭代器的空间。
代码非原创,稍稍做了改动而已。
========================================================================
MemPool.h
#ifndef
_MEM_POOL_H
#define
_MEM_POOL_H
#include
<vector>
#include
<iostream>
using
namespace
std;
/*
在内存池中分配固定大小的内存块
目的是加速内存分配速度,并且减少因重复分配相同
*/
class
CMemPool
{
public
:
//创建大小为blockSize的内存块,内存池数目为预分配的数目preAlloc
CMemPool(
int
blockSize,
int
preAlloc
= 0,
int
maxAlloc
= 0);
~CMemPool();
//获取一个内存块。如果内存池中没有足够的内存块,则会自动分配新的内存块
//如果分配的内存块数目达到了最大值,则会返回一个异常
void
*
Get();
//释放当前内存块,将其插入内存池
void
Release(
void
*
ptr);
//返回内存块大小
int
BlockSize()
const
;
//返回内存池中内存块数目
int
Allocated()
const
;
//返回内存池中可用的内存块数目
int
Available()
const
;
private
:
CMemPool();
CMemPool(
const
CMemPool&);
CMemPool&
operator = (
const
CMemPool&);
enum
{
BLOCK_RESERVE
= 128
};
typedef
std::vector<
char
*>
BlockVec;
int
m_blockSize;
int
m_maxAlloc;
int
m_allocated;
BlockVec
m_blocks;
};
inline
int
CMemPool::BlockSize()
const
{
return
m_blockSize;
}
inline
int
CMemPool::Allocated()
const
{
return
m_allocated;
}
inline
int
CMemPool::Available()
const
{
return
(
int
)
m_blocks.size();
}
#endif
=========================================================
MemPool.cpp
#include
"MemPool.h"
CMemPool::CMemPool(
int
blockSize,
int
preAlloc,
int
maxAlloc):
m_blockSize(blockSize),
m_maxAlloc(maxAlloc),
m_allocated(preAlloc)
{
if
(
preAlloc < 0 || maxAlloc == 0 || maxAlloc < preAlloc )
{
cout<<
"CMemPool::CMemPool
parameter error."
<<endl;
}
int
r
= BLOCK_RESERVE;
if
(preAlloc
> r)
r
= preAlloc;
if
(maxAlloc
> 0 && maxAlloc < r)
r
= maxAlloc;
m_blocks.reserve(r);
for
(
int
i
= 0; i < preAlloc; ++i)
{
m_blocks.push_back(
new
char
[m_blockSize]);
}
}
CMemPool::~CMemPool()
{
for
(BlockVec::iterator
it = m_blocks.begin(); it != m_blocks.end(); ++it)
{
delete
[]
*it;
}
}
void
*
CMemPool::Get()
{
if
(m_blocks.empty())
{
if
(m_maxAlloc
== 0 || m_allocated < m_maxAlloc)
{
++m_allocated;
return
new
char
[m_blockSize];
}
else
{
cout<<
"CMemPool::get
CMemPool exhausted."
<<endl;
return
(
void
*)NULL;
}
}
else
{
char
*
ptr = m_blocks.back();
m_blocks.pop_back();
return
ptr;
}
}
void
CMemPool::Release(
void
*
ptr)
{
memset
(ptr,0,
sizeof
(
char
)*m_blockSize);
//内存回收回来以后并没销毁,原数据仍在,所以应该清空
m_blocks.push_back(
reinterpret_cast
<
char
*>(ptr));
}
=========
main.h
#include
"stdafx.h"
#include
"MemPool.h"
#include
<string.h>
int
main(
int
argc,
char
*
argv[])
{
CMemPool
*m_cache =
new
CMemPool(50,0,10);
char
*
src_date=
"abcdefg"
;
char
*p1=(
char
*)(m_cache->Get());
char
*p2=(
char
*)(m_cache->Get());
int
*p3=(
int
*)(m_cache->Get());
strcpy
(p1,src_date);
strcpy
(p2,src_date);
p3[0]=9;p3[1]=25;
m_cache->Release(p1);
m_cache->Release(p2);
m_cache->Release(p3);
//把MemPool.cpp中void
CMemPool::Release(void* ptr) 的
//memset(ptr,0,sizeof(char)*m_blockSize);注释掉可以验证每次内存回收以后是重复利用而非销毁
cout<<*(
int
*)(m_cache->Get())<<endl;
cout<<(
char
*)(m_cache->Get())<<endl;
cout<<(
char
*)(m_cache->Get())<<endl;
delete
m_cache;
return
0;
}
完毕!
当然这只是探究内存池而已,更高级的比如线程安全,内存扩容,模板等等,仍需解决。
但是相信想初窥内存池门径应该还是有帮助的!