zoukankan      html  css  js  c++  java
  • 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

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

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

    由于环境不同关系,并非所有的博客内容都会上传完整的源码,大部分的源码,大家可以到我的github主页上的UGCFramework查找

    传送门:https://github.com/wulonghao/UGCFramework
  • 相关阅读:
    CSS3 实现六边形Div图片展示效果
    自己编写jQuery插件 之 放大镜
    自己编写jQuery插件 之 无缝滚动
    C#装箱拆箱
    C#基础知识
    数据库锁
    SQL2008中Merge的用法
    SQl去获取相同记录
    判断DataRow中是否包含某列
    Quartz中时间表达式的设置-----corn表达式
  • 原文地址:https://www.cnblogs.com/unityExplorer/p/7574569.html
Copyright © 2011-2022 走看看