服务器开发之内存 小片内存的管理

服务器开发之内存<小片内存的管理

 

 

 

说个大白话: 一个程序要运行起来,首先要从cpu要首先从磁盘中把程序加载的到内存,当运行起来的时候,要从内存再到cpu的缓存,cpu的缓存还有多级,之所以硬件方面有这样的设置,是因为他们之间每层之间的速度有着数量级的差别。

 

下面以三国杀的数据服务器为例子说明服务器内存的一些特点:

我简称为:sgs

 

<1> sgs数据服务器的特点:

 

sgs的数据服务器提供从数据库加载和保存玩家数据的功能,提供稳定,可靠,速度快的性能特点。

Sgs用户的数据特点,每个用户有上百个物品,上百个战功,几十个任务,几十个好友,等等一些属性数据,一个用户平均有几百个小的数据块信息。每个数据块可能几十个字节到几百个字节不等。一个数据服务器提供两万个用户的数据服务,那么一个逻辑进程大概要管理几百万个这样的小数据块。

Sgs数据服务器的另外一个特点就是每秒种都有用户不停的上线,下线,一天上下线的次数会有几十万次。

数据服务器需要长时间的运行,一般会一个月更新一次版本,当没有版本更新的时候一个月可能更长的时间是不需要重新启动。

 

<2>sgs数据服务器的上面这些特点,对内存方面的要求,必须是没有内存的泄露,如果有内存的泄露,肯定是程序运行一段时间就会因为内存分配不到而发生宕机。造成玩家的数据丢失等严重事故。

 

<3> 我的解决方案。

     考虑到sgs数据服务器的运行特点,我分析的是它的一个运行周期的特点,一个运行周期是一个月。服务器启动后,在每天的一个时间段会达到当天的人数高峰期,就好比餐馆的午餐时间,肯定是餐馆最繁忙,并非最好的时候。一直周末会的一个时间,服务器会达到这个周的最高峰,其实杭州的外婆家也是这样,周五的晚上会是这周的最高峰,每个月新功能上线的当天,会是这个月的最高峰,好比我们的节假日,饭店,旅游地区会达到这个运行周期的最高峰。

这些就是我们的数据服务器在一个运行周期里面所要经历的考验,也是它的运行特点。

我说了,这么多的废话,落实到内存上,其实就是说每当我们的运行周期,出现这些高峰的时候也是我们内存需求最大的时候。

     

下面的图是我所开发的数据服务器的人数和所分配的内存对应图标。你可以可以看到,这个内存模型是只分配不释放的一个模型。为什么我会选择这个的模型呢,当然了,这是数据服务器的运行特点决定的,上面我简单的说了一下数据服务器一个运行周期里面的数据特点。那么这种内存模型有什么特点,或者说好处。种子模型会降低cpu频繁的出现分配和释放内存的操作,降低因为程序的长期运行而增加内存碎片。会降低进程工作集的每日内存增量。

 

 图片插入不了,就加了个附件。

线面图标里面黑色的表示在线人数。

蓝色表示服务器所使用的内存,就是数据服务器所分配的内存。

 

 

下面说说,这些内存的分配和管理是如何实现的:

这个类是整个系统的内存分配接口,系统所有的内存都必须从这里分配出去,这个你可以添加内存的监控,统计,容错等等接口。

 

这个接口只是提供了应用层的统一入口管理,下面说说如何实现底层的内存分配。因为sgs数据服务器管理的是数量比较多的小块内存,所以我的处理是以最小单位为4k进行分配,然后在以固定的大小分配成小块小块的内存,

 

 

class XSmallBlockMg

{

public:

XSmallBlockMg( unsigned int _blocksize,

              unsigned int _scmax_count,

              unsigned int _scstep=1000){}

~XSmallBlockMg(void){}

 

Char malloc();

void  free(charpObj);

    Int   gettotalcount();  //统计分配和管理的内存块数目

};

 

 

 

 

//通用的分配池

typedef char * PpUint;

typedef map<PpUint,intMapMemPP;

class CNormalAllocXMg

{

protected:

CNormalAllocXMg(){}

virtual ~CNormalAllocXMg(){}

 

public:

static CNormalAllocXMg &single()

   {

       static   CNormalAllocXMg gsdllmg;

       return  gsdllmg

   }

 

public:

char  * mallocunsigned int ma_size ){}

bool   freechar *pobjint marktype ){}

template<class A>A *new_0xx(){}

template<class A,typename PARAM0 >A *new_1xxPARAM0 param0 ){}

    

private:

MapMemPP  m_map_pvoid//用来检查,防止重复释放

//         小块内存的大小

typedef map<unsigned int,XSmallBlockMg*> MAP_POOLITEM;

};

 

XSmallBlockMg用来管理单一大小的内存块,比如长度32个字节长度的内存块,这个对象负责管理在使用的和空闲的内存块,当申请这个大小的内存块不足够使用的时候,就会申请新的内存,但申请后的内存是不会在释放的。

CNormalAllocXMg 是所有内存的申请入口,当我们申请一个内存的时候,它会找到一个大小最适合这个内存块大小的XSmallBlockMg对象来实现内存的分配,

CNormalAllocXMg 里面内存快的大小从816,32,64,128,256,512,这样的大小递增下去,当然你也可以根据你的逻辑数据的大小进行最合理的定制,在sgs里面最大的数据块不大于256,大部分在32上下左右。

 

 

最后的注意:你可以添加你自己的接口函数,添加自己需要的功能,比如

(a)添加一个内存各种大小块的统计功能,用来估计是否有内存泄漏,如果根据

(b)需要注意的是,这个池的设计是不能中途对内存进行释放的。这点请务必注意,如果你需要释放,就需要你添加整块的内存处理和管理。

你可能感兴趣的:(ccc:游戏服务器)