(转载)简单linux C++内存池

来源:互联网 发布:mac怎么点亮键盘 编辑:程序博客网 时间:2024/05/21 11:16
C++代码
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
在学习内存池的过程中可谓云游太虚。一般都是针对标准内存池再次实现。大部分以链表的形式讨论。诚然最正宗也最准确,但是相对比较晦涩,本文是针对刚刚接触内存池的同学写的。大大减少了对内存池整体认识的难度。
  
内存池:
如果程序中涉及频繁申请释放内存,并且每次使用的内存并不是很大,这时候应该考虑内存池。
内存池可以有有效的避免内存碎片的产生。
内存池的框架:
classMemPool{
public:
MemPool(){初始化分配N个小的内存块}
~MemPool(){真正删除整个分配了的内存空间}
void* getmem(){获取内存(块)}
voidfreemem(){释放内存到内存池中,这里并不是真正的释放掉内存,只是回收再利用;}
private:
structLinkBlock * 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>   
usingnamespace std;  
  
/* 
    在内存池中分配固定大小的内存块  
    目的是加速内存分配速度,并且减少因重复分配相同  
*/  
  
classCMemPool  
{  
public:  
      
    //创建大小为blockSize的内存块,内存池数目为预分配的数目preAlloc   
    CMemPool(intblockSize, intpreAlloc = 0, intmaxAlloc = 0);  
      
    ~CMemPool();  
      
    //获取一个内存块。如果内存池中没有足够的内存块,则会自动分配新的内存块   
    //如果分配的内存块数目达到了最大值,则会返回一个异常   
    void* Get();  
      
    //释放当前内存块,将其插入内存池   
    voidRelease(void* ptr);  
      
    //返回内存块大小   
    intBlockSize() const;  
      
    //返回内存池中内存块数目   
    intAllocated() const;  
      
    //返回内存池中可用的内存块数目   
    intAvailable() const;  
      
private:  
    CMemPool();  
    CMemPool(constCMemPool&);  
    CMemPool& operator = (constCMemPool&);  
      
    enum  
    {  
        BLOCK_RESERVE = 128  
    };  
      
    typedefstd::vector<char*> BlockVec;  
      
    intm_blockSize;  
    int        m_maxAlloc;  
    int        m_allocated;  
    BlockVec    m_blocks;  
};  
  
inlineint CMemPool::BlockSize()const  
{  
    returnm_blockSize;  
}  
  
inlineint CMemPool::Allocated()const  
{  
    returnm_allocated;  
}  
  
inlineint CMemPool::Available()const  
{  
    return(int) m_blocks.size();  
}  
#endif  
  
=========================================================
MemPool.cpp
  
  
#include "MemPool.h"   
CMemPool::CMemPool(intblockSize, intpreAlloc, intmaxAlloc):  
m_blockSize(blockSize),  
m_maxAlloc(maxAlloc),  
m_allocated(preAlloc)  
{  
    if( preAlloc < 0 || maxAlloc == 0 || maxAlloc < preAlloc )  
    {  
        cout<<"CMemPool::CMemPool parameter error."<<endl;  
    }  
      
    intr = 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(newchar[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;  
            returnnew char[m_blockSize];  
        }  
        else  
        {  
            cout<<"CMemPool::get CMemPool exhausted."<<endl;  
            return(void *)NULL;  
        }  
    }  
    else  
    {  
        char* ptr = m_blocks.back();  
        m_blocks.pop_back();  
        returnptr;  
    }  
}  
  
  
voidCMemPool::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>
intmain(int argc, char* argv[])
{
CMemPool *m_cache =newCMemPool(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;
deletem_cache;
    return0;
}
  
完毕!
  
当然这只是探究内存池而已,更高级的比如线程安全,内存扩容,模板等等,仍需解决。
但是相信想初窥内存池门径应该还是有帮助的!
描述:以STL-vector为数据存储单元,实现简单的内存池功能。
原创粉丝点击