初探NetGame(四):服务器内存管理
续上在这里我将要向大家简单介绍一下游戏服务器中必须要处理另外一项主要技术:
内存分配处理技术也可以称为内存池处理技术(这个比较洋气,前面通俗的好,呵呵)
开始向大家介绍一般情况下我们对于内存的一些基本操作。简单而言,内存操作就只有三个步骤:申请、使用、销毁。而对于这些操作我们在C和C++中的处理方式略有不同:
在C中我们一般用malloc(….)函数来进行申请,而对应销毁已经申请的内存使用free(…)函数。
在C++我们一般使用new操作符和delete操作符进行处理申请和销毁。
大家一定要问了,我们一般都是这样处理的呀!!没有什么可以说的哦!!呵呵,我感觉就有还是有一些东东和大家聊的哦。先聊简单几条吧!!
1.Malloc(…..)和free(….), new ….和 delete …必须成对出现不可以混杂哦,混杂的话,后果就不可以想了哦!!(也没有什么,就是内存被泄漏了,呵呵)
2.在我们使用new …和delete ….一定要注意一些细节,否则后果同上哦!!什么细节呢?下面看一个简单的例子:
char *block_memory = NULL;
block_memory = new char[1024];
delete block_memory;
block_memory = NULL;
大家沉思一会。。。。。。。。。
大家看有错吗?没有错吧!!
如果说没有错的,就要好好补补课了,是有错的,上面实际申请的内存是没有完全被释放的,为什么呢?因为大家没有注意第一条的完全匹配原则哦,在new 的时候有[ ],我们在delete 怎么就没有看见[ ] 的影子呢? 这就造成了大错有1023个字节没有被释放。正确的是 : delete []block_memory;
关于内存基本操作的我是说这两条,其他要注意还是有的,基本就源于此了。
了解了上面那些接下来就想大家说说服务器内存处理技术了。上面都没有弄清楚了,就算了。呵呵。
大家都知道,我们的服务器要频繁的响应客户端的消息同时要将消息发送到客户端,并且还要处理服务器后台游戏World的运行。这样我们就必须要大量的使用内存,并且要进行大量的内存操作(申请和销毁)。而在这样的操作中,我们还必须要保证我们的绝对正确无误,否则就会造成内存的泄漏,而内存泄漏对于服务器而言是非常可怕的,也可能就是我们服务器设计失败的毒药。而我们如何进行服务器内存的正确和合理的管理呢?那就是我们
必须建立一套适合我们自己的内存管理技术。现在就向大家说一说我在内存管理方面的一些做法。
基本原理先用图形表示一下:
上面的意思是:我们在服务器启动过程中就为自己申请一块比较大的内存块,而我们在服务器运行过程中需要使用内存我们就到这样一块比较大已经申请好的内存块中去取。而使用完后要进行回收。原理就是这么简单。而最重要的是我们如何管理这个大的内存块呢?
(非常复杂也比较难,呵呵)
首先 就内存块操作而言就只有申请(类似 new)和回收(类似 delete)。
其次 我们必须要清楚那些内存我们在使用中,那些是可以申请的。
关于上面我简单将这样的一些数据结构和class定义在下面供大家参考使用。
typedef struct MemoryBlock //内存块结构
{
void *buffer; //内存块指针
int b_Size; //内存块尺寸
} MemoryBlock;
class CMemoryList //列表对象类(相当于数组管理类)
{
public:
CMemoryList();
virtual ~ CMemoryList();
void InitList(int data_size,int data_num);//初始化列表数据结构尺寸和数量
void AddToList(void *data); //加入列表中
void DeleteItem(int index); //删除指定索引元素
……………..
private:
void Init();
void Release();
private:
void *memory;
int total_size;
int total_num;
protected:
};
classs CMemoryPool //内存池处理类
{
public:
CMemoryPool();
virtual ~ CMemoryPool();
bool InitMemoryPool(int size); //初始化内存池
void * ApplicationMemory(int size); //申请指定size内存
void CallBackMemory(void *,int size); //回收指定size内存
private:
void Init();
void Release():
MemoryBlock *UniteMemory(MemoryBlock *block_a,MemoryBlock * block_b); //合并内存
private:
MemoryBlock memoryPool_Block; //内存池块
CMemoryList *callBackMemory_List; //回收内存列表
CMemoryList *usingMemory_List; //使用中内存列表
CMemoryList *spacingMemory_List; //空白内存列表
protected:
};
以上就是这个内存管理类的一些基本操作和数据定义,class CMemoryList 在这里不是重点暂且就不说了,有空再聊。而具体的内存池处理方法简单叙述如下:
函数InitMemoryPool(): 初始化申请一块超大内存。
函数ApplicationMemory():申请指定尺寸,申请内存成功后,要将成功申请的内存及其尺寸标示到usingMemory_List列表,同时要将spacingMemory_List列表进行重新分配。以便于正确管理。
函数CallBackMemory():回收指定尺寸内存,成功回收后,要修改spacingMemory_List列表,同时如果有相邻的内存块就要合并成一个大的内存块。usingMemory_List修改使用列表,要在使用列表中的这一项删除。
以上就是一些简单处理说明,更加详细的就需要大家自己琢磨和处理了。我就不细说了。