记录一则线上bug
来源:互联网 发布:php include没用 编辑:程序博客网 时间:2024/04/29 06:25
最近线上出现一次崩溃事故,core在了dynamic_cast类型转化上面,之前一直跑的好好的,第一反应是存在野指针了。
void RoomHandler::KickAllPlayersInRoom(Room* room){ vector<IPlayer*> players = room->GetPlayers(); for (size_t i=0; i<players.size(); i++) { ProcessPlayerQuit(dynamic_cast<Player*>(players[i]), room); }}
经过仔细排查并没有发现释放完后,没有在容器中删除的情况。
其中的GetPlayers大概是这种结构:
std::vector<IPlayer*> Room::GetPlayers(){ std::vector<IPlayer*> v; for( PlayerContainer::iterator it = _players.begin(); it != _players.end(); ++it){ v.push_back( it->second ); } return v;}
_players是一种map类型,上面的函数实际上就是把map中的数据复制一份到vector中,现在要做的很显然就是把_players打印出来,嗯,标准的gdb并不能打印出来需要的(值,数据)信息,下面的是红黑树中的一些基本元素,要解析出来可以试着强制转换才能打印。
(gdb) print room._players$8 = { _M_t = { _M_impl = { <std::allocator<std::_Rb_tree_node<std::pair<unsigned int const, IPlayer*> > >> = { <__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, IPlayer*> > >> = {<No data fields>}, <No data fields>}, members of std::_Rb_tree<unsigned int, std::pair<unsigned int const, IPlayer*>, std::_Select1st<std::pair<unsigned int const, IPlayer*> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, IPlayer*> > >::_Rb_tree_impl<std::less<unsigned int>, false>: _M_key_compare = { <std::binary_function<unsigned int, unsigned int, bool>> = {<No data fields>}, <No data fields>}, _M_header = { _M_color = std::_S_red, _M_parent = 0x0, _M_left = 0x954e7d0, _M_right = 0x954e7d0 }, _M_node_count = 0 } }}
有工具是可以直接打印stl的,需要去下载一个文件,可以去参考一下http://blog.csdn.net/luoleicn/article/details/5968038
然后我们就可以打印map中的东西了:
(gdb) pmap room._players <int> //只考虑第一个元素Map size = 0
让人惊讶的蛋疼的事情发生了,Map的空的!
难道多线程下被其他线程改写了?可实际上我们的游戏主逻辑是单线程的,所有的数据库线程读取都是使用回调的。然后又去仔细研究了一下回调,目前的的回调是在epoll的主循环中处理的,这里会处理所有已完成的数据库操作的队列。所以实际上还是在一个线程中完成的。
顺序执行感觉根本不该出现这种情况,在这种束手无策的情况下,只能一句句代码开始分析,找了一两个小时终于发现问题的根源出现在ProcessPlayerQuit上,这个函数调用的层次非常的深,这个函数会清除room中player信息,并且处理一些玩家在不在房间或者不在游戏的情况,在其中某一个分支上竟然会再次调用到KickAllPlayersInRoom。
在循环之初就已经清除掉了room._players之中的元素,第二轮调用到的时候dynamic_cast尝试解引用一个已经删除的元素就core掉了。
现在的问题就有点像下面这种情况。
vector<IPlayer*> players = room->GetPlayers(); //从 room._players获取玩家 for (size_t i=0; i<players.size(); i++) { //某一个分支会出现 //第二次到这的时候room._players就已经清空掉了。 for (size_t j =0; j<players.size(); j++) { //room._players.erase(uid); } }
- 记录一则线上bug
- 线上bug记录
- HttpClient线上bug
- beanshell 线上修复BUG
- ios 定位线上bug
- iOS线上修复bug
- 关于线上bug
- 记录微软的BUG一则--Repeater里的RadioButtonList不可以局部刷新
- nginx线上问题记录
- 线上问题记录
- 项目线上Bug处理流程
- 写了一个线上bug
- 一则线上MySql连接异常的排查过程
- 一则线上MySql连接异常的排查过程
- 记一则很bug的小事
- 记录BUG
- bug 记录
- bug记录
- python requests.get() 下载大文件
- jQuery名称冲突解决方法
- 奖品的价值 Erasing and Winning
- 怎样写出漂亮整洁的代码?聊聊clean code的编码、重构技巧
- 正向表模板
- 记录一则线上bug
- Codeforces 366D Dima and Trap Graph(搜索剪枝/二分)
- Multi view adapter
- 去除list集合中重复项的几种方法
- 羽翼metasploit第一,二季学习笔记
- SoapUI使用方法-01发送http请求
- JPA——映射优化
- 第五届蓝桥杯【省赛试题7】六角填数
- 英文金曲大赛