http://my.csdn.net/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.csdn.net/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;
}
完毕!
当然这只是探究内存池而已,更高级的比如线程安全,内存扩容,模板等等,仍需解决。
但是相信想初窥内存池门径应该还是有帮助的!