昨天公司项目做小规模的测试,测试功能以及真实环境中的服务器稳定性,开服半小时后,战场服务器崩溃。崩溃的时候没有任何日志留下,按正常情况,我们服务器的每一个线程都有异常捕获机制,并能将现场dump出来,保存为dmp文件,并将调用堆栈打印出来,保存为log文件。但任何日志都没有被留下。
碰到这个情况让我非常的头疼,因为毫无疑问,导致这种问题的原因肯定是和堆被破坏有关,堆被破坏后,任何有内存分配的行为都将失败。
我不得不在服务器上装好vs的社区版,只安装调试工具,大概1.9个g的空间需求对服务器60g的硬盘也是不小的压力。
我再次启动战场服务器,然后用vs attach到进程,等待下一次崩溃,看能不能抓到现场。不出所料,大约20分钟之后,服务器又崩溃了,这次没有任何异常被捕获到,只是在vs的输出最下方输出了一个错误 0xC0000374。
查了一下这个错误代码的含义,果然不出我所料,就是堆内存被破坏导致,这种情况一般是越界写内存导致的。这种bug无疑是最难调试的几种bug之一。
想了一下,还是决定把服务器的page heap选项打开,虽然会消耗更多内存,但可以在服务器写越界的时候直接抛异常。这样就可以准确的定位故障点。
把 Enable page heap, Enable heap tail checking, Enable heap free checking, Enable heap paramater checking, Enable heap validation on call 这几个全部勾选上。
然后关闭gflags,把战场服务器重新启动,如果设置成功了,最明显的标志就是内存消耗,战场服务器之前的提交大小是400多mb,现在的内存提交大小是2.9G。明显增加了几倍。这是为了调试堆的额外开销。
然后再用vs attach到服务器,静待出错的异常。
大约半小时后,战场服务器抛出了异常,被vs捕获到了,vs提示我将代码定位好,定位好代码之后,发现了出现这次bug的地方。
这一段代码看的我哭笑不得,这种应该属于灯下黑吧,反复检查了几次的代码都看不到问题所在。
CMemory data;
U32 length = message -> ReadU32();
if( length ) {
data.Alloc( data ); // 出错的地方。
}
if( data )
{
if( length ==
message -> ReadBytes(data, length) )
{
data.SetLength( length );
}
}
data可以被造型为指针,空的data返回的是NULL,被理解为0,如果输入0,则data会缺省的分配4096字节,大部分情况下,这个部分的代码不会出问题,如果超过4096字节,就会导致越界,从而导致堆内存被破坏。于是用Alloc做关键字查询了整个项目,又发现了几处这种写法。显然是复制粘贴导致的结果。
把这些地方全部修正之后,再将服务器启动,运行了一下午,服务器稳定了,没再崩溃了。看来可以享受一个安静的周末了。:)
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- hzar.cn 版权所有 赣ICP备2024042791号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务