博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
处理由引用计数引起的泄漏
阅读量:6231 次
发布时间:2019-06-21

本文共 3349 字,大约阅读时间需要 11 分钟。

网游服务器的逻辑一般来说比较复杂,而且在很多情况下还使用了多线程,因此使用基于引用计数的智能指针能很大程度的减少内存泄漏和对象失效等问提.

但是基于引用计数的指针在很多情况下也会产生另一种情况的泄漏,例如:网游中有一个代表角色的类型character,角色的对象在网游中可以说是最常见的对象

之一了,与几乎所有的游戏逻辑都有关系,因此,一个角色对象可能会存在于很多容器,或被其它的对象所持有,为了保证角色对象的有效性,常常会使用基

于引用计数的智能指针来存放角色对象。问题由此产生了,例如当一个角色离开地图,我们就需要把所有指向这个角色的智能指针清0,稍有不甚,漏掉一个都

会导致资源无法释放,而且要找到具体还被哪些地方持有是相当麻烦的事情.

在我们项目中,处理这种情况的做法是,不使用智能指针来存放对象,而是采用了另外一种叫做ident的对象.对象被创建之后,只由一个容器持有其原始对象,

其它的所有外部引用持有的都是那个由原始对象产生的ident对像.当逻辑需要使用原始对象时,通过ident转换成原始对象,如果原始对象依旧有效则返回原始

对象,否则,返回NULL。首先,原始对象是基于引用计数的对象,其中有一个64位的identity成员,其高32位是一个全局计数器的值,低32位是一个时间戳.对象被创建的时候,

identity被正确的初始化,被销毁时将identity置0,这样,两个对象identity拥有相同值的概率是相当低的.

然后看下ident对象,只有一备份的identity和一个指向原始对象的指针,通过make_ident函数,可以通过一个原始对象的指针产生一个ident对象.然后,

可以通过cast_2_refbase将一个ident对象转换回原始指针,如果转换成功,原始对象的引用加1,防止对象正在使用的时候被其它线程释放掉.只要在

使用完毕后调用ref_decrease清理即可.

refbase.h

 

#ifndef _REFBASE_H#define _REFBASE_H#include 
#include
#include
#include
#include "atomic.h"extern atomic_32_t global_counter;struct refbase{ atomic_32_t refcount; atomic_64_t identity; atomic_32_t flag; void (*destroyer)(void*);};void ref_init(struct refbase *r,void (*destroyer)(void*),int32_t initcount);static inline atomic_32_t ref_increase(struct refbase *r){ return ATOMIC_INCREASE(&r->refcount);}static inline atomic_32_t ref_decrease(struct refbase *r){ atomic_32_t count; if((count = ATOMIC_DECREASE(&r->refcount)) == 0){ r->identity = 0; _FENCE; int32_t c = 0; for(;;){ if(COMPARE_AND_SWAP(&r->flag,0,1)) break; if(c < 4000){ ++c; __asm__("pause"); }else{ struct timespec ts = { 0, 500000 }; nanosleep(&ts, NULL); } } r->destroyer(r); } return count;}typedef struct ident{ uint64_t identity; struct refbase *ptr;}ident;static inline ident make_ident(struct refbase *ptr){ ident _ident = {ptr->identity,ptr}; return _ident;}static inline ident make_empty_ident(){ ident _ident = {
0,NULL}; return _ident;}static inline struct refbase *cast_2_refbase(ident _ident){ while(_ident.identity == _ident.ptr->identity) { if(COMPARE_AND_SWAP(&_ident.ptr->flag,0,1)) { struct refbase *ptr = NULL; if(_ident.identity == _ident.ptr->identity && ref_increase(_ident.ptr) > 0) ptr = _ident.ptr; _FENCE; _ident.ptr->flag = 0; return ptr; } } return NULL;}static inline int32_t is_vaild_ident(ident _ident){ if(!_ident.ptr || !_ident.identity) return 0; return 1;}#define TO_IDENT(OTHER_IDENT) (*(ident*)&OTHER_IDENT)#endif

 

refbase.c

#include "refbase.h"#include "SysTime.h"atomic_32_t global_counter = 0;void ref_init(struct refbase *r,void (*destroyer)(void*),int32_t initcount){    r->destroyer = destroyer;    r->identity = ATOMIC_INCREASE(&global_counter);    r->identity <<= 32;    r->identity += GetSystemMs();    r->refcount = initcount;}

 

大致处理逻辑如下:

ident _ident;struct ref_base *atker = cast_2_refbase(_ident);if(atker){    //对象依然有效,执行某些逻辑 ......    ref_decrease(&atker);//不再使用了,减少计数  }else{       //原对象已经失效}

转载地址:http://ngmna.baihongyu.com/

你可能感兴趣的文章
httpd配置文件httpd.conf规则说明和一些基本指令
查看>>
python中self cls init的理解
查看>>
java:类集操作总结
查看>>
Flake8学习
查看>>
SpringBoot项目eclipse运行正常maven install打包启动后报错ClassNotFoundException
查看>>
ASP.NET Core的身份认证框架IdentityServer4(9)-使用OpenID Connect添加用户认证
查看>>
[Python] String Formatting
查看>>
lapis 处理接收到的json 数据
查看>>
【spring boot logback】日志使用自定义的logback-spring.xml文件后,application.properties中关于日志的相关配置还会起作用么...
查看>>
Ad Hoc Distributed Queries的启用与关闭
查看>>
java工具类POI导出word
查看>>
openwrt使用list
查看>>
shell语言
查看>>
C++动态分配内存
查看>>
Android Studio工程Gradle编译报错
查看>>
桌面小部件开发
查看>>
Unity3d dll 热更新 基础框架
查看>>
spring boot整合mybatis+mybatis-plus
查看>>
深度学习利器:TensorFlow在智能终端中的应用——智能边缘计算,云端生成模型给移动端下载,然后用该模型进行预测...
查看>>
如何查看表和索引的统计信息
查看>>