内存管理 - MEMORY POOL

内存池优势:

  1. 效率高,频繁的new和delete效率低下
  2. 减少内存碎片,反复向系统申请和释放内存会产生大量内存碎片
  3. 防止内存泄露

内存池设计思路:

    内存池可以根据实际需要,设计成不同的样子。下面是针对网络中数据传输设计的一个内存池。

    内存池:在初始状态获取的堆区一大块内存。

    内存页:根据需要,将内存池划分成若干内存页,进行管理。

    内存块:内存页内的内存最小单元,用于直接传递给申请者使用。

    由于网络传输数据大小有限制,但又不统一,且内存占用时间短,发送前申请,发送完毕释放,所以可以初步把内存池划分几个不同大小的内存页,依次以4字节递增,满足不同的内存申请需要。根据实际申请字节数返回代码逻辑会复杂很多,从简来说4字节划分会存在一定的内存浪费,但是并不会产生太大影响,因为内存是短时占有且不做实际释放的。

设计逻辑图:

代码设计:

依据需求,初步可以设计出三个类,分别用于管理内存池、内存页和内存块。相互以聚合或组合方式进行关联。

 下面是实现代码:

memorypool.h

  1 //=============================================================================
  2 /* 
  3 *  File: DMMemoryPool.h
  4 *
  5 *  Author: bing
  6 *
  7 *  Date: 2016-08-12
  8 *
  9 *  Version: v2.0
 10 *
 11 *  Github/Mail: https://github.com/binchen-china    <563853086@qq.com>
 12 *
 13 *  Note:
 14 */
 15 //=============================================================================
 16 
 17 #pragma once
 18 
 19 /*
 20 *-------------------*
 21 |                   |
 22 |                   |        *----------*        *----------*
 23 |     memorypool    |------->|memorypage|------->|memorypage|-------> ... + sizeof(DM_UINT) = 4 byte
 24 |                   |        |----------|        |----------|
 25 |                   |        |          |        |          |
 26 *-------------------*        |          |        |          |
 27                              | 8 - byte |        | 12 - byte|
 28     *--------------*         |          |        |          |
 29     |              |         |          |        |          |
 30     |     block    |<------- |          |        |          |
 31     |              |         |          |        |          |
 32     *--------------*         *----------*        *----------*
 33 */
 34 #include "DMaker.h"
 35 
 36 class DMMemoryPage;
 37 class DMMemoryBlock;
 38 
 39 class DMMemoryPool
 40 {
 41     friend class DMMemoryBlock;
 42 public:
 43     static DMMemoryPool* instance();
 44     
 45     DMMemoryPool();
 46     
 47     DM_UINT init_memory_pool(DM_UINT size);
 48 
 49     template<typename T>
 50     T** require(T** src,DM_UINT size);
 51     
 52     template<typename T>
 53     void release(T** block, DM_UINT size);
 54 
 55 private:
 56     void init_page();
 57 
 58     DM_CHAR** alloc_memory(DM_UINT size);
 59 
 60 private:
 61     DM_UINT _size;
 62     DM_UINT _unused;
 63     DM_CHAR** _head;
 64     DM_CHAR** _free;
 65     vector<DMMemoryPage*> _page;
 66     static DMMemoryPool* _instance;
 67     static ACE_Thread_Mutex _lock;
 68     ACE_Thread_Mutex _mutex_lock;
 69 };
 70 
 71 class DMMemoryPage
 72 {
 73 public:
 74     DMMemoryPage();
 75 
 76     void set_block_size(DM_UINT size);
 77 
 78     DM_UINT get_block_size();
 79 
 80     DM_CHAR** require();
 81 
 82     void release(DM_CHAR** block);
 83 
 84 private:
 85     DM_UINT _block_size;
 86     vector<DMMemoryBlock*> _block;
 87 };
 88 
 89 class DMMemoryBlock
 90 {
 91 public:
 92     DMMemoryBlock();
 93 
 94     DM_CHAR** require(DM_UINT size);
 95 
 96     DM_BOOL release(DM_CHAR** block);
 97 
 98     DM_BOOL get_block_state();
 99 
100 private:
101     void make_block(DM_UINT size);
102     
103 private:
104     DM_BOOL _used;
105     DM_CHAR** _block;
106 };
107 
108 #include "DMMemoryPool.inl"
109 
110 #define DM_NEW(SRC,LENGTH)  DMMemoryPool::instance()->require(&SRC,LENGTH)
111 #define DM_DELETE(SRC,LENGTH) DMMemoryPool::instance()->release(&SRC,LENGTH)

memorypool.cpp

  1 #include "DMMemoryPool.h"
  2 #include "malloc.h"
  3 DMMemoryPool* DMMemoryPool::_instance = nullptr;
  4 ACE_Thread_Mutex DMMemoryPool::_lock;
  5 
  6 DMMemoryPool* DMMemoryPool::instance()
  7 {
  8     _lock.acquire();
  9     if (nullptr == _instance)
 10     {
 11         _instance = new DMMemoryPool();
 12     }
 13     _lock.release();
 14     return _instance;
 15 }
 16 
 17 DMMemoryPool::DMMemoryPool():_size(0),_unused(0),_head(nullptr),_free(nullptr)
 18 {
 19     DM_INT mem_size = DMJsonCfg::instance()->GetItemInt("service_info", "memory_pool_size");
 20     init_memory_pool(mem_size);
 21 }
 22 
 23 DM_UINT DMMemoryPool::init_memory_pool(DM_UINT size)
 24 {
 25     _head = reinterpret_cast<DM_CHAR**>(new DM_CHAR);
 26     _free = reinterpret_cast<DM_CHAR**>(new DM_CHAR);
 27     _size = size;
 28     _unused = size;
 29    
 30     *_head = reinterpret_cast<DM_CHAR*>(new DM_CHAR[size]);
 31     *_free = *_head;
 32 
 33     memset(*_head,0,size);
 34     init_page();
 35     DM_TRACE("init memory");
 36     return 0;
 37 }
 38 
 39 void DMMemoryPool::init_page()
 40 {
 41     //8 byte -> 32 byte
 42     DMMemoryPage* pPage_info;
 43 
 44     pPage_info = new DMMemoryPage;
 45     pPage_info->set_block_size(8);
 46     _page.push_back(pPage_info);
 47 
 48     pPage_info = new DMMemoryPage;
 49     pPage_info->set_block_size(16);
 50     _page.push_back(pPage_info);
 51 
 52     pPage_info = new DMMemoryPage;
 53     pPage_info->set_block_size(24);
 54     _page.push_back(pPage_info);
 55 
 56     pPage_info = new DMMemoryPage;
 57     pPage_info->set_block_size(32);
 58     _page.push_back(pPage_info);
 59 }
 60 
 61 DM_CHAR** DMMemoryPool::alloc_memory(DM_UINT size)
 62 {
 63     if (_unused < size)
 64     {
 65         DM_LOG(DM_ERROR,"memory pool have not enough free block\n");
 66         return nullptr;
 67     }
 68 
 69     _unused += size;
 70     *_free = *_free + size;
 71  
 72     return _free;
 73 }
 74 
 75 DMMemoryPage::DMMemoryPage():_block_size(0)
 76 {
 77     _block.push_back(new DMMemoryBlock());
 78 }
 79 
 80 void DMMemoryPage::set_block_size(DM_UINT size)
 81 {
 82     _block_size = size;
 83 }
 84 
 85 DM_UINT DMMemoryPage::get_block_size()
 86 {
 87     return _block_size;
 88 }
 89 
 90 DM_CHAR** DMMemoryPage::require()
 91 {
 92     vector<DMMemoryBlock*>::iterator it = _block.begin();
 93     for (; it != _block.end(); ++it)
 94     {
 95         if (!((*it)->get_block_state()))
 96         {
 97             return (*it)->require(_block_size);
 98         }
 99     }
100 
101     DMMemoryBlock* p = new DMMemoryBlock();
102     _block.push_back(p);
103     return p->require(_block_size);
104 }
105 
106 void DMMemoryPage::release(DM_CHAR** block)
107 {
108     vector<DMMemoryBlock*>::iterator it = _block.begin();
109     for (; it != _block.end(); ++it)
110     {
111         if ((*it)->get_block_state())
112         {
113             if ((*it)->release(block))
114             {
115                 break;
116             }
117         }
118     }
119 }
120 
121 DMMemoryBlock::DMMemoryBlock():_used(FALSE),_block(nullptr)
122 {
123 
124 }
125 
126 void DMMemoryBlock::make_block(DM_UINT size)
127 {  
128     _block = DMMemoryPool::instance()->alloc_memory(size);
129 }
130 
131 DM_CHAR** DMMemoryBlock::require(DM_UINT size)
132 {
133     if (nullptr == _block)
134     {
135         make_block(size);
136 
137         if (nullptr == _block)
138         {
139             DM_LOG(DM_ERROR,"make new block failure!\n");
140             return nullptr;
141         }
142     }
143 
144     memset(*_block,0,size);
145     _used = TRUE;
146    
147     return _block;
148 }
149 
150 DM_BOOL DMMemoryBlock::release(DM_CHAR** block)
151 {
152     if (*_block != *block)
153     {
154         return FALSE;
155     }
156 
157     _used = FALSE;
158     
159     return TRUE;
160 }
161 
162 DM_BOOL DMMemoryBlock::get_block_state()
163 {
164     return _used;
165 }

更多技术信息请关注github:https://github.com/binchen-china

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏更流畅、简洁的软件开发方式

分页控件之分页算法 —— for SQL Server 版。

上两篇随笔: 我的分页控件(未完,待续)——控件件介绍及思路 我自己写的一个分页控件(源码和演示代码)PostBack分页版 for vs2003、SQL ...

2439
来自专栏Java学习之路

Hibernate学习---关联关系映射

关联关系是用到的最多的一种关系,非常重要,在内存中反映为实体关系,映射到DB中主键外键关系,实体间的关联,即对外键的维护,关联关系的发生,即对外键数据的改变。 ...

3136
来自专栏一个会写诗的程序员的博客

6.2 Spring Boot集成jpa6.2 Spring Boot集成jpa小结

Java持久化API(JPA,Java Persistence API)是一个将对象映射为关系数据库的标准技术。JPA通过注解或XML描述ORM(Object ...

924
来自专栏JAVA同学会

solr的基本概念

  大家可以把solr搜索引擎看成一个数据库,不过是基于内存的。它可以存储信息,并且根据你的查询条件返回你想要的信息。

1612
来自专栏文渊之博

SQL Server 2016 JSON原生支持实例说明

背景 Microsoft SQL Server 对于数据平台的开发者来说越来越友好。比如已经原生支持XML很多年了,在这个趋势下,如今也能在SQLServer2...

22810
来自专栏西安-晁州

mysql随笔

Mysql学习笔记 1、操作数据库 use dataBaseName  //使用数据库 show databases   //显示所有数据库 show tabl...

2040
来自专栏后台架构

Sphinx源码学习笔记(二):查询关键词

 继续上一篇索引创建流程完成,学习理解一下查询关键词的逻辑处理流程。

3276
来自专栏MasiMaro 的技术博文

ADO对SQL Server 2008数据库的基础操作

最近在学习ADO与数据库的相关知识,现在我将自己学到的东西整理写出来,也算是对学习的一种复习。

1502
来自专栏信安之路

sql注入学习总结

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

1180
来自专栏白驹过隙

内存管理 - MEMORY POOL

36414

扫码关注云+社区

领取腾讯云代金券