HEAP: Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed
2016-06-22 23:24
351 查看
《诸子百家》发布后,发现游戏在有些情况下会崩溃。偶然崩溃。
由于我是负责主框架,网络协议和登录,数据等,所以这个修正bug的任务主要就落在我头上了。
一、bug
1.最头疼的bug
HEAP: Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed
这个是最头疼的。知道崩溃了,知道内存地址,但是不知道在哪个文件。跟踪了好几天,打了很多日志,没头绪。后来网络上一找,也有很多人碰到这个问题。主要的解决方案是下载使PageHeap.EXE或GFlags.EXE检查内存越界错误,还有就是用WinDbg.
于是屁颠屁颠的把这些都下下来,搞了一阵子,发现不实用。主要是我们游戏里面,代码文件还是蛮多的,300多个文件,代码行估计有20万行~ 这个里找错误还真不好找,工具也没办法定位到具体的文件。
想了很久,后来觉得自己把问题想的太复杂了。
上面的错误很典型的就是内存已经被释放了,后面还继续使用。简单点说就是野指针!而造成野指针的原因很简单,就是内存被释放了。
于是,问题变简单了:找出所有释放内存的地方。
释放内存的,主要就2个:free和delete.
于是,我使用了2个宏,S_DEL(p) if(p){delete p; p=NULL;}
S_FREE(p) if(p){free(p); p=NULL;}
然后把所有用到这两个的地方都用宏替换掉,然后再把这两个宏里面真正释放的给注释掉。再跑,发现很OK,不会崩溃了。 于是,确认了是释放引起的。
然后在逐个把两个宏里的释放打开,发现打开S_FREE没问题,于是范围缩小到S_DEL里了。然后再把S_DEL里的释放也打开,再按照模块,把可以的地方用到的那个S_DEL注释掉~~ 这个样折腾了好久,最终找到了bug
2. 郁闷的bug
有时在团战的时候,发现打到一定阶段,程序就崩溃了。查看内存,看起来也没什么特殊的。。。
然后也是很长时间的排查。。。。。
二.具体总结
1. 经过很久的排查和使用上面的方法后,终于把这些崩溃点都解决了。主要有3个bug:
1).AMF3协议里面。我们使用独立的内存分配器进行内存的分配和释放,保证不内存泄漏。内存不泄露这个目标是达到了,但是有时把正在用的内存给释放掉了,造成了野指针。
为什么会把正在使用的内存给释放掉了呢?原来,在AMF3里,有一些数据是用引用的方式,而我们进行功能改写时,使用了同样的引用的方式,造成了多个节点使用同一个内存,因此导致其中某一个节点把这内存释放后,其他使用这个的都变成野指针了。
解决方案:不要使用引用,每个使用独立的内存
2)战斗里面,我们有一些战斗进度是用OnRender进行驱动的。比如A含有5个B,B含有10个C,我们的战斗进度的驱动之一是是C的OnRender()。而OnRender是一直循环调用的,用这进行驱动的时候,如果符合了某一个条件,比如战斗结束,那C通知B,B通知A,A就释放内存,通知结束。这种模式的问题是,A释放内存后,C返回到战斗结束的触发点继续运行就崩溃了~
解决方案:检测到战斗结束时,要所有的模块退出OnRender,然后才释放内存~
3)用户注销重新登录时,有时崩溃。
原因是用户注销时,我们会把所有的内存释放掉,把socket关闭。但是可能我们把内存释放掉时,由于socket还在,所以继续收到数据包进行AMF3的解析,而解析结果已经部分被清掉了,这个时候访问,野指针,崩溃~~
改成先把socket关闭,然后内存再释放掉。发现,有时还是会崩溃~~ 后来发现,因为我们的socket是单独线程处理的,也就是说我们释放内存和关闭sockt的操作是在2个线程里处理,这样总会出现一个先,一个后的,如果释放内存比关闭socket先执行,则还是会出现野指针。
解决方案:在socket线程里进行socket的释放,等socket释放完毕才进行内存的释放~
由于我是负责主框架,网络协议和登录,数据等,所以这个修正bug的任务主要就落在我头上了。
一、bug
1.最头疼的bug
HEAP: Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed
这个是最头疼的。知道崩溃了,知道内存地址,但是不知道在哪个文件。跟踪了好几天,打了很多日志,没头绪。后来网络上一找,也有很多人碰到这个问题。主要的解决方案是下载使PageHeap.EXE或GFlags.EXE检查内存越界错误,还有就是用WinDbg.
于是屁颠屁颠的把这些都下下来,搞了一阵子,发现不实用。主要是我们游戏里面,代码文件还是蛮多的,300多个文件,代码行估计有20万行~ 这个里找错误还真不好找,工具也没办法定位到具体的文件。
想了很久,后来觉得自己把问题想的太复杂了。
上面的错误很典型的就是内存已经被释放了,后面还继续使用。简单点说就是野指针!而造成野指针的原因很简单,就是内存被释放了。
于是,问题变简单了:找出所有释放内存的地方。
释放内存的,主要就2个:free和delete.
于是,我使用了2个宏,S_DEL(p) if(p){delete p; p=NULL;}
S_FREE(p) if(p){free(p); p=NULL;}
然后把所有用到这两个的地方都用宏替换掉,然后再把这两个宏里面真正释放的给注释掉。再跑,发现很OK,不会崩溃了。 于是,确认了是释放引起的。
然后在逐个把两个宏里的释放打开,发现打开S_FREE没问题,于是范围缩小到S_DEL里了。然后再把S_DEL里的释放也打开,再按照模块,把可以的地方用到的那个S_DEL注释掉~~ 这个样折腾了好久,最终找到了bug
2. 郁闷的bug
有时在团战的时候,发现打到一定阶段,程序就崩溃了。查看内存,看起来也没什么特殊的。。。
然后也是很长时间的排查。。。。。
二.具体总结
1. 经过很久的排查和使用上面的方法后,终于把这些崩溃点都解决了。主要有3个bug:
1).AMF3协议里面。我们使用独立的内存分配器进行内存的分配和释放,保证不内存泄漏。内存不泄露这个目标是达到了,但是有时把正在用的内存给释放掉了,造成了野指针。
为什么会把正在使用的内存给释放掉了呢?原来,在AMF3里,有一些数据是用引用的方式,而我们进行功能改写时,使用了同样的引用的方式,造成了多个节点使用同一个内存,因此导致其中某一个节点把这内存释放后,其他使用这个的都变成野指针了。
解决方案:不要使用引用,每个使用独立的内存
2)战斗里面,我们有一些战斗进度是用OnRender进行驱动的。比如A含有5个B,B含有10个C,我们的战斗进度的驱动之一是是C的OnRender()。而OnRender是一直循环调用的,用这进行驱动的时候,如果符合了某一个条件,比如战斗结束,那C通知B,B通知A,A就释放内存,通知结束。这种模式的问题是,A释放内存后,C返回到战斗结束的触发点继续运行就崩溃了~
解决方案:检测到战斗结束时,要所有的模块退出OnRender,然后才释放内存~
3)用户注销重新登录时,有时崩溃。
原因是用户注销时,我们会把所有的内存释放掉,把socket关闭。但是可能我们把内存释放掉时,由于socket还在,所以继续收到数据包进行AMF3的解析,而解析结果已经部分被清掉了,这个时候访问,野指针,崩溃~~
改成先把socket关闭,然后内存再释放掉。发现,有时还是会崩溃~~ 后来发现,因为我们的socket是单独线程处理的,也就是说我们释放内存和关闭sockt的操作是在2个线程里处理,这样总会出现一个先,一个后的,如果释放内存比关闭socket先执行,则还是会出现野指针。
解决方案:在socket线程里进行socket的释放,等socket释放完毕才进行内存的释放~
相关文章推荐
- apache的两种工作模式详解
- BroadcastReceiver组件的使用
- 关于ListView和GridView默认阴影
- 阅读笔记
- @WebServlet Servlet3.0新特性
- java爬取百度图片
- 吧
- Android 选择图片,加载图片,显示图片 综合案例
- Android系统透明栏(Translucent Bars)使用SystemBarTint的实现攻略
- BZOJ 1443 [JSOI2009]游戏Game | UVALive 5882 Racing Car Trail
- 层次式性能分析器XHProf
- 流加密的密文解密
- matlab 交换矩阵的行和列
- Python: 安装库的简单方法——pip install ...
- 格式转换说明符scanf,printf格式%大全/格式化输入输出
- 事务隔离级别小记
- Linux学习之CentOS(十三)--CentOS6.4下Mysql数据库的安装与配置
- 错误 mysqli::real_connect(): (HY000/2002): No such file or directory
- nginx使用小记
- application详解