unity探索者之protobuf的序列化和反序列化导致unity崩溃的问题研究

版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/7574569.html

这两天博主在接微信支付SDK的时候碰到一个非常恶心又诡异的问题——proto序列化和反序列化的无辜崩溃

上图就是博主遇到这个问题时正在调试微信支付的核心协议,博主在序列化和反序列化该消息的字节组时,unity就会立马崩溃,遇到过unity崩溃的朋友应该都知道,unity会给出两个用于查找问题的文件,一个crash.dmp和一个error.log

error.log文件会输出堆栈的二进制数据,表示看不懂,所以只能看crash.dmp这个错误报告文件了

如果电脑上装了vs,可以直接打开,打开后显示如下

提示的意思简单点说就是内存越界,然而,经过博主调试后发现导致unity崩溃的函数就是protobuf-net.dll提供的反序列化函数

----> Serializer.Serialize<IExtensible>();

然而直到这个并没有什么卵用,因为根本无法锁定到问题的核心所在

于是博主开始各种尝试:

首先,怀疑命名问题,因为协议中定义了一些看起来可能会冲突的名字:比如package

于是,博主注释掉这些看起来可疑的属性,包括appId、return_code、return_msg、err_code、err_code_des、package,结果是依然崩溃

然后继续注释掉notify_url、sign,结果没有崩溃

所以博主开始怀疑是notify_url、sign这两个属性搞的鬼,于是分开取消注释测试,发现不论取消注释哪一个,都会崩溃

好吧,凌乱了,毫无头绪,尤其是在随便更改这些属性的命名后都一样后就更加没有头绪了

所以最后不得不得出结论:并不是命名的问题

再想到文件大小的问题,博主为了省事,将所有的协议全部打包到一个cs文件中,最终这个文件有378kb,8000+行代码,这个量严格来说不算大,毕竟过万行代码的多得是

但是确实也想不到其他的可能了

按照这个思路,博主将最终生成的类文件分成多个,测试后发现还是崩溃

那么也不是文件大小的问题,这下就无奈了,错误报告太简单,解决方案也太诡异,实在无法找到错误原因,按道理unity的日志应该不会这么简单

于是,就去查unity自己的日志文件,地址如下

打开后,总算发现了一些端倪

在日志文件最底部,崩溃前的堆栈日志说明,崩溃的元凶就是proto的序列化,但是最后的utf16_to_utf8_len是什么鬼,博主表示看不懂

但是意思应该就是编码格式的转换问题了

回到协议内容一看,发现这个协议有个特点,全都是string,好吧,虽然这个可能有点扯,并且可能还不是核心,但是先试试吧

把所有的类型全部换成int,奇迹出现了,没有崩溃

再来,全部还原,然后只把appId的类型改成int,结果没有崩溃

好吧,貌似是类型全都是string的原因,但是前面只有4个属性的时候没有崩溃又是什么原因,况且也并不是没有出现过全部都是string的协议

再试试别的可能,比如修改必要性,把appId改为required等等等。。。。

经过一番测试,终于得出了如下结论(unity版本5.6.2,protobuf-net.dll版本2.3.2):

单个协议全部是optional string的情况下

修改其中一条属性类型为int或bool时,不会崩溃
修改其中一条属性为required时,不会崩溃
减少单个协议的属性数量到4个,不会崩溃,超过或等于5个,崩溃

总结:所有属性全为optional时,属性类型不能全部为string,反之则不能全为optional

上面的问题不知道大家有没有遇到过,希望大家没有遇到过,一次就能恶心半天了。

虽然问题解决了,但还是知其然不知其所以然,如果有朋友知道本质原因,希望可以分享

posted @ 2017-09-22 15:06  半颗星辰  阅读(886)  评论(0编辑  收藏  举报