??xml version="1.0" encoding="utf-8" standalone="yes"?> Ҏ(gu)l验Q这是一个典型的栈破坏问题。一旦栈破坏?jin)函数返回值后Q堆栈完全是错ؕ的,得不CQ何有效信息?br />最开始我目l的同事查看最q提交的代码Q看看能否找到线索。不q由于近一个月提交的代码实在太多,大v捞针?jin)一D|间后Q?br />毫无头A?br /> 栈覆盖一般是因ؓ(f)memcpy或者是循环赋D句导致的Q一般栈覆盖的层ơ不?x)太多,所以从底部往(xin)上找Q应该能扑ֈ些有效的U烦(ch)?br />不过Q由于服务器函数l常?x)有Package的(f)时变量,D函数栈很大,从下往(xin)上找U烦(ch)也很困难Q很多似是而非的合法地址很容易分散精力?br /> 按照上面的分析,从底部往(xin)上找是大h针,那么从顶部往(xin)下找如何呢? Z(jin)说明Bug产生的原因,先描qC场景理的实现方式吧?/span> Ҏ(gu)上面的描qͼ如果一切按照正常程序,q个Ҏ(gu)q{是没问题的。最初上U的时候,也没有出现问题,但是在出?jin)一个资料片之后Q服务器基本上每隔半时左右׃(x)发现有死循环或者宕机问题?/span> 原因
解决
q里先说明下一般函数堆栈的徏?未优化情况下的用户函?:
push rbp
mov rbp, rsp
从这里可以看出,本层函数的返回值是存储?[rbp + 8]Q而上层函数的rbp地址则存储在 [rbp]?br />所以,从下|上扄时候,可以Ҏ(gu)rbp逐步扑ֈ上层函数和上层函数的堆栈帧?br />
那么如何往(xin)下找呢,假如知道?jin)一个上层函数的rbpQ如何获取下层函数呢Q?br />q里有个窍门,gdb7.X的版本有一个find功能Q可以在内存区域搜烦(ch)数|
从上往(xin)下找的时候,可以在堆栈查找本?rbp的存攑֜址Q从而确定下层函数rbp的存攑֜址?br />举个例子:
q是一个典型的CallStack,让我们先扑ֈ0x000000000040072b的堆栈信息吧?br />?info r 查看当前的寄存器信息:
只有一个地址Q那么存放rbp的地址是0x7fffffffe540?jin)?br />
验证下是否正:(x)
x/10xg 0x7fffffffe530
看到?jin)吧Q就是这hC(jin)下一U的函数?br />真实环境中往(xin)往(xin)没这么简单,有时候会(x)扑ֈ好几个地址Q这个时候需要自己逐个M存真?jin)?br />
]]>场景理
2、场景的q播是采取经典的?ji)宫格方式来实现的,每一个格子的我们定义为Area对象,一个场景的格子l成其实是一个二l数l?/span>
3、玩家进入场景的时候,Ҏ(gu)坐标可以知道要进入哪个格子,每个格子内会(x)保留一个Head指针Q标记最新进入的玩家对象。玩家对象上?个指针,标记玩家所在格子的前一个和后一个对象。可以通过格子内的Head指针便利Area内的所有玩家对象?/span>
4、玩家移动切换格子的时候,先从原来的格子内LeaveQ这?x)调用原来Area对象的Leave函数。再q入新的格子Q调用Area的Enter函数。很明显QLeave函数是一个链表删除操作,如果玩家是HeadQ则讄新的Head?/span>
Enter操作是新q入的玩安接到原队列里Q新q入的玩家会(x)被设|ؓ(f)Head?/span>问题表现
原因
]]>
辛苦是因?011基本上是加了(jin)一q班Q从q完q开始,?012q过q前最后一周,q一q来Q是我感觉最辛苦的一q_(d)好在最l?/span>
目是打了(jin)个翻w仗Q心(j)里ȝ有了(jin)些慰藉?br />
2011q游戏经历从技术封、内、公到整改、重新内公,一路走来,遇到无数E奇古怪的BugQ?/span>
有时候压力大的时候,晚上都睡不着Q脑子里回想着现场的一丝丝蛛丝马迹Q希望能扑ֈbug的原因,l历q无数次l望到重生的喜?zhn)Q也有被猜忌不信ȝ痛苦Q活p是一部部侦探剧情?/span>
没有从事q游戏开发或者游戏没上线的同学很隄?bug有这么难扑Q的,如果是简单的I指针宕机,当然是好扄Q用我们的话Q这c问题是个傻子都能解?其实不然Q很多时候直接原因是I指针,
真正的原因隐藏很?Q但是更多的是隐藏很q问题Q需要反复的分析现场Q假讑։情才能得到灵感,然后推演Q才可能得到l果Q当?dng)q个和游戏逻辑的复杂度是分不开的?/span>
具体的bugl节不便在此分析Q但是大部分的问题,其实都是因ؓ(f)不正常的设计引v的,所以其实我一直在思考,在Y件开发领域,其实也存在着"?,说通俗点叫客观规律Q不按照道行事,q早是要受到惩罚的?/span>
但是在游戏后台开发中Q很多时候存在不同技术方案的矛盾Q难以让人取舍,q些矛盾都是真实在很多项目存在的?/span>
很多开发者由于担?j)内存泄Ԍ在项目中止使用动态内?当然q实际上几乎是做不到?Q用对象池来避免动态内存,是预先创徏预计最大数量的对象Q后l申请和归还的时候,都是操作对象池,
避免动态new和delete。这L(fng)目q(sh),我见q的好几个。对象池的好处是显而易见的Q基本上可以避免内存泄露。但是实际上Q这U方式是把双刃剑Q个得在游戏目中,q种方式弊大于利?br />主要弊端有下面几点:(x)
1、开发不方便Q导致需要添加很多的对象池管理类Q即使有模板帮忙Q也是非常繁琐的。实际开发中Q几乎不可能对这些小对象c都搞一个对象池理cR?br />
2、由于采用预先生成对象,一般会(x)预估一个对象可能存在的最大数量,然后按照最大数量来创徏Q浪费内存?br /> 的确Q你没有内存泄露Q但是你启动的时候就需要好几个G的内存,q个是内存浪费,好在现在server开发基本都?4位,没有地址I间的困C(jin)Q但是,在大部分情况下浪费好几个G的内存,
光想想都有点?j)疼?br />
3、引入了(jin)新的风险Q由于采用对象池Q申h对象的时候,只是单的pop一个空闲对象就可以?jin),很容易漏掉对象初始化的工作,在回收对象的时候,大部分开发者也很容易漏掉清理工作,或者初始化?br />清理工作q于单,q样Ҏ(gu)D新对象被历史操作影响。曾l遇到过一个新FB所有传送点都打不开的问题,是因ؓ(f)历史对象回收时数据没清理D的?br />
回头来看对象池的优点Q很多开发者坚持是Z(jin)解决内存片和内存泄霌Ӏ先说内存碎片,暂且不说内存片真的是否有这么严重,退一步,其实内存片已经有很多的成熟解决Ҏ(gu)?jin),自己重蝲smallObjectq是
采用标准的tcmalloc解决Q都是非常轻杄。至于内存泄Ԍ个h觉得q个问题其实是很好查的,也是c++E序员的基本要求?/span>
q个问题单独提出来,几乎所有h都会(x)_(d)当然是分模块针对接口开发了(jin)。和天下所有的事情一P知易行难。由于游戏逻辑目影响的地斚w常多Q比如死亡的时候,既需要判断死亡掉落,又需要处理Q务状态,
如果在战场和竞技ZQ还要判断基数和得分{等Q这导致很多开发者不假思烦(ch)的把所有的东西都揉在一P你中有我Q我中有你,我改你的代码你改我的?/span>
一个最单的例子Q我在项目中开发掉落功能,当把物品d到玩家背包后Q发现客L(fng)没有更新背包Q一查,居然q需要掉落的开发者自己构造数据包同步客户端,其实作ؓ(f)其他模块Q根本不兛_(j)背包数据同步的细节?/span>
q个其实在现实生zM很常见,我委托背包模块添加一个物品,具体的细节是被由被委托(sh)h来负责的。将q多的细节交l其他模块处理,?x)导致复杂度增加Q容易出现问题,对其他h来说Q也是一个精力浪费,如果是一个复?/span>
模块Q你?x)发现需要了(jin)解太多的l节Q修改太多自׃熟?zhn)的代码,q而导致风险。还有一U观点,认ؓ(f)一锅粥的开发方式有助于?jin)解游戏的各个业务模块,对这U观点,我是不以为然的,每天陷入到繁琐的l节Q真的对熟?zhn)业务有好处吗Q或?dng)R下来玩玩游戏更有帮助Q而且Q这么ؕ的代码,看v来也是非常篏的。分模块开发,具体的办法,游戏~程_a(b)5上有文章写得很好,q里不扩展了(jin)?/span>
真的需要禁用STL?/span>
不止一ơ在和其他项目交的资料里看到对方很威严的宣U在目里禁止用STL。说实话Q我q真没觉得STL有什么不好。见q太多这c项目自己重复实C个个y脚的排序算法、容器等{?br />大部分h一般都?x)根据经验选择使用自己熟?zhn)的技术,q个无可厚非Q但是像q样明着止使用STLQ真不知道如何能理直气壮。其实大部分不用STL的理由,基本上都是不熟?zhn)Q完全没有够的理由止使用?/span>
游戏开发无技术含量?
曄多次听到行业内的兄弟有此感慨Q确实,游戏逻辑复杂度非帔RQ架构上大部分都是类似的。但是这q不说明游戏后台开发复杂度不高Q如何将游戏开发逻辑复杂剥离开来,做到E_高效开发,其实q是有很?br />东西可以探讨的,看看那些目Q大部分都是一锅粥Q需要什么功能就蛮干Q加上去Q这L(fng)实毫无技术含量,都是蛮干。所以,一件事情是否有技术含量,不光是看事情本nQ还要看怎么qԌ蛮干和苦qԌ那是最没有技?br />含量的方式了(jin)Q程序员q是要有强烈?#8220;h”意识?/span>
void fun1()
{
fun();
}
void fun2()
{
fun1();
}
void fun3()
{
fun2();
}
最后,我们在main函数里执行fun3,注意~译的时候带?rdynamic 选项?span class=Apple-style-span style="WORD-SPACING: 0px; FONT: medium Simsun; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">