unity 微信网页版登录后闪退登录,游戏闪退,为什么

崩溃的情况
进入游戏一会儿,神马都不要做,双手离开手机,盯着屏幕看吧,游戏会定时从服务器那儿读取一些数据,时间一长,闪退了。尼玛问题是神马呢?完全没有头绪,不过大体猜测是因为网络请求导致的,那么好,先排查服务器返回结果是否有问题,最终确认每次客户端崩溃的时候,服务器都成功的返回了格式正确的数据,没有任何异常。那么可以确定问题是出在客户端部分了。 先检查代码,确认逻辑上没有任何问题之后,也倍感无力啊,问题依然在重现。肿么办呢?
确定具体原因
那么好吧,打一个测试版本再来看,然后再等着崩溃,查看崩溃日志吧,最终看到的崩溃日志中,崩溃线程输出信息如下:
Thread 27 Crashed:
0 libsystem_kernel.dylib 0x38e671fc __pthread_kill + 8
1 libsystem_pthread.dylib 0x38ecea4e pthread_kill + 54
2 libsystem_c.dylib 0x38e18028 abort + 72
3 gowonline 0x mono_handle_native_sigsegv + 312
4 gowonline 0x01779a30 mono_sigsegv_signal_handler + 256
5 libsystem_platform.dylib 0x38ec9720 _sigtramp + 40
6 gowonline 0x00114f48 m_RestSharp_Http_ExecuteCallback_RestSharp_HttpResponse_System_Action_1_RestSharp_HttpResponse + 52
7 gowonline 0x m_RestSharp_Http_RequestStreamCallback_System_IAsyncResult_System_Action_1_RestSharp_HttpResponse + 900
8 gowonline 0x00329c60 m_2be7 + 48
9 gowonline 0x00a39d08 m_System_Net_WebAsyncResult_DoCallback + 76
10 gowonline 0x00a29628 m_System_Net_HttpWebRequest_SetWriteStream_System_Net_WebConnectionStream + 536
11 gowonline 0x00a46f84 m_System_Net_WebConnection_InitConnection_object + 708
12 gowonline 0x0101ffac m_wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
13 gowonline 0x mono_jit_runtime_invoke + 2152
14 gowonline 0x mono_runtime_invoke + 132
15 gowonline 0x mono_runtime_invoke_array + 1448
16 gowonline 0x mono_message_invoke + 444
17 gowonline 0x mono_async_invoke + 124
18 gowonline 0x async_invoke_thread + 312
19 gowonline 0x start_wrapper + 496
20 gowonline 0x thread_start_routine + 284
21 gowonline 0x GC_start_routine + 92
22 libsystem_pthread.dylib 0x38ecdc5a _pthread_body + 138
23 libsystem_pthread.dylib 0x38ecdbca _pthread_start + 98
好的,那么已经确定是在我们使用的一个第三方类库 RestSharp 中出现的问题,问题是出现在一个 Action 回调的地方。那么这种问题为什么会出现呢,那我们就得好好得来找找原因了。
关于如何查看 iOS 崩溃日志,让崩溃日志更加友好,我们可以参考这篇文章,,主要就是要确保你的设备上跑着的这个 App 的编译和打包的二进制文件要在你用于查看日志的 Mac 上,这样的话,当我们查看崩溃日志的时候,Xcode 会自动将那些无法阅读的函数调用的堆栈信息转化成可读性较强的日志信息,帮助还是很大的。
那么这个时候我们可以通过将设备连接到 Mac 上,直接通过 Xcode 将程序编译并运行,多尝试着玩一段时间,当程序再次出现崩溃的时候,我们就能看到更清楚的函数调用关系了,同时也能看到更多的日志提示。
最终能确定每次崩溃的函数就是这个 mono_convert_imt_slot_to_vtable_slot,这个看上去就是 Mono Runtime 在将接口声明的方法指针指向实际实现这个接口的对方的方法,我们可以找到 mono_convert_imt_slot_to_vtable_slot 这个方法所在的文件查看一下,这个方法就在 Mono 项目的目录 mono/mini/mini-trampolines.c 中可以找到。
在 Xcode 中崩溃时,会输出类似& SIGABRT (ERROR:mini-trampolines.c:183:mono_convert_imt_slot_to_vtable_slot: code should not be reached) & 的日志,看着很像是原本是要执行某个方法,但是不知道因为什么原因这个方法就无法访问到了,好奇葩啊。
现在虽然已经知道了问题出现的地方,但是貌似完全看不明白的样子,尼玛 trampoline 都还是第一次听说耶,那么先请教一个我大 Google 吧,我们总是相信自己不是那第一个吃螃蟹的人,所以我们找到了一位大神的解决方案就在
,大神的文章写得非常言简意赅,大体意思就是如果你在做 Unity3D 开发时,特别是在针对 iOS 和 Android 平台的时候,你很有可能会碰到比较杯具的就是程序会莫名其妙地闪退哦,不过不要着急,这个通常就是因为你的程序编译的时候给 trampoline 分配的空间太小,而你的程序中又大量使用了泛型、泛型方法调用和接口实现导致的。然后给出了具体的解决方法,那就是在 Unity3D 的编译选项 Player Setting 中有一个 AOT Compilation Options 条目,在这个选项条目中加上以下编译参数就好了
nrgctx-trampolines=8192,nimt-trampolines=8192,ntrampolines=4096
然后再重新一下,多多测试吧,骚年。关于这三个参数的意思呢,大神也给出了解释,分别如下:
nrgctx-trampolines=8192 这是留给递归泛型使用的空间,默认是 1024
nimt-trampolines=8192 这是留给接口使用的空间,默认是 128
ntrampolines=4096 这是留给泛型方法调用使用的空间,默认是 1024
Mono Runtime AOT 机制剖析
虽然问题貌似已经得到解决了,而且我们貌似也搞清楚了具体原因就是因为默认 Mono Runtime 在 AOT 编译的时候给的 trampoline 配置太小,不适合我们这种设计优良,大量使用 interface,设计绝对遵照 OO 思想的稍大一些的项目呢。那么我们以后是不是在做 Unity3D 开发的时候就尽量少用接口呢?是不是我们就尽量少用泛型和泛型方法呢?
既然这么感兴趣,想问个究竟,那么我们就来好好看看这个 AOT 到底是个神马东西吧,尼玛为什么就这么复杂,这么隐蔽,这么折腾人,《铁血战神》在 App Store 上线都 5 个月了有木有,尼玛这个问题碰到也不是一次两次了有木有,作为程序猿的我们被玩家吐槽了很多次,我们的客服 XDJM 们为我们背了多少黑锅啊,我勒个去啊。
首先,还是先搞定这个 trampoline 吧,毕竟问题的根源是在它身上的,那么我们就好好来看看这是个神马东西。我们找到 Mono Runtime 的官方文档中关于 trampoline 的描述来看看吧。
Trampolines are small, hand-written pieces of assembly code used to perform various tasks in the mono runtime. They are generated at runtime using the native code generation macros used by the JIT. They usually have a corresponding C function they can fall back to if they need to perform a more complicated task. They can be viewed as ways to pass control from JITted code back to the runtime.
翻译一下吧:
Trampoline 是一些手写的非常短小的用来在 mono 运行时中执行很多操作的组件代码。主要是通过 JIT 使用到的本地代码宏在运行时动态生成的。它们通常都有与之相对应的 C 方法,在某些较为复杂的场景中,当 trampoline 无法胜任时,mono 运行时就会将这些复杂的操作交回给这些对应的 C 方法来执行。这也可以看作是将 JIT 代码的执行权交回给 runtime 的一种方式。
好吧,貌似还没有太明白,那么这个 Trampoline 为什么会导致出现闪退的问题的,这看起来明显是为了提高 mono runtime 在执行 C#代码时候的效率啊。
那么我们再来看看官方文档关于 JIT Trampolines 和 AOT Trampolines 的介绍吧,杯具的 IMT Trampolines 介绍还在//TODO 状态中。
JIT Trampolines These trampolines are used to JIT compile a method the first time it is called. When the JIT compiles a call instruction, it doesn&t compile the called method right away. Instead, it creates a JIT trampoline, and emits a call instruction referencing the trampoline. When the trampoline is called, it calls mono_magic_trampoline () which compiles the target method, and returns the address of the compiled code to the trampoline which branches to it. This process is somewhat slow, so mono_magic_trampoline () tries to patch the calling JITted code so it calls the compiled code instead of the trampoline from now on. This is done by mono_arch_patch_callsite () in tramp-.c.
好吧,再翻译一下吧。
JIT Trampolines 这些 Trampoline 主要是 JIT 在首次调用某个方法的时候编译方法用的。当 JIT 在编译一个方法调用指令时,它并不会立刻就编译这个被调用到的方法。实际上,它会先创建一个 JIT Trampoline,同时创建一个指向这个 trampoline 的调用指令。当这个 JIT Trampoline 在调用到的时候,它会再调用 mono_magic_trampoline() 方法来编译这个 trampoline 实际指向的目标方法,然后将编译后的方法的指针地址返回给这个指向它的 trampoline。这个过程呢稍微有点慢,所以呢,mono_magic_trampoline() 方法会优化调用 JIT 代码的过程,它会先尝试调用已经通过 JIT 编译过的方法而不是立即通过 trampoline 直接进行调用。这些都是通过在 tramp-.c 文件中的 mono_patch_callsiete() 方法来完成的。
这就是 JIT Trampolines 的机制,接下来我们看看 AOT Trampolines 又是怎么一回事呢。
AOT Trampolines
These are similar to the JIT trampolines but instead of receiving a MonoMethod to compile, they receive an image+token pair. If the method identified by this pair is also AOT compiled, the address of its compiled code can be obtained without loading the metadata for the method.
再翻译一下。
AOT Trampolines AOT Trampolines 和 JIT Trampolines 非常相似,但是 AOT Trampolines 接受的编译参数不是一个 Mono 方法而是一个 image+token 对。如果传入的用于编译的 image+token 对所指向的方法已经经过 AOT 编译过了,那么再次编译这个 image+token 对时,就会直接返回这个已编译方法的指针地址而不需要再次加载这个方法的元数据进行再次编译了。
好吧,看了这么多关于 Trampoline 相关的内容,貌似只是了解到了非常有限的内容,那就依然是 Trampolines 存在的价值就是为了减少 C#代码在 mono runtime 中运行时的性能损耗,提高 C#代码的执行效率。
还有那个没有出场的 IMT Trampolines 应该也就是用于优化接口调用效率的小『蹦床』吧。
那么我们在开发 Unity3D 游戏的时候通常都会发布到 iOS 设备和 Android 设备上,而 Unity3D 在 iOS 和 Android 设备上的发布都选择了使用 AOT 编译机制来实现。那么显然我们碰到的 Trampolines 问题都是跟 AOT Trampolines 有关,那么 AOT 又是神马呢?
AOT 就是区别于 JIT(Just In Time) 的另一个编译机制,全称是 Ahead Of Time,就是预先编译好,而不是在代码执行到了某个方法再进行编译,这样的话会有一些好处。
,使用 AOT 编译的有点有以下优点: 1. 加快程序启动速度 2. 更强的内存共享机制 3. 潜在的性能提升
当然也会有一些限制,例如支持平台的有限,支持 AOT 的 Mono 版本有限等等,具体信息可以参考
那么回到我们最开始的问题,为什么我们的游戏就会出现崩溃呢?好吧,现在一点点回顾吧。
我们出现的问题是偶尔会出现闪退,根据崩溃日志我们能定位到是 mono_convert_imt_slot_to_vtable_slot 这个方法导致的,然后我们再通过 Xcode 跟踪到了是 trampoline 无法被访问到的问题。
那么这么高端大气上档次的问题是肿么出现的呢?貌似 Mono 还算是个不错的产品啊,还是很活跃的啊,也有专门的公司 Xamarin 在支撑着,怎么就会出现这种问提呢?
好吧,程序都是人写的,有问题也是很正常的。上面的分析已经很清楚了,大体的原因就是因为 Mono 在 iOS/Android 等移动设备上使用了 AOT 这种机制,为什么选择这种机制?原因非常简单,那就是可以针对特定平台编译成在平台优化的字节码,在资源比较紧缺的移动平台上还是有着明显优势的。而使用 AOT 编译就需要为 Trampolines 这些小东西留足足够的空间,当然这个肯定是硬编码的某个常数啦,在整个程序加载成功运行之后,该常数就成为了 Trampolines 运行时的配置。AOT 默认编译时给 Trampolines 的参数有点低:
nrgctx-trampolines 默认为 1024
nimt-trampolines 默认为 128
ntrampolines 默认为 1024
这对于小一些的项目可能是够用的,因为整体项目的结构不会太复杂,使用到的接口、泛型、递归相对也不会太多,但是对于一个稍大一些的项目来说,特别是采用了某些设计良好的第三方库的项目来说,这就比较纠结了。
其实我们在项目中就使用了两个第三方的库,一个是 CodeTitan.JSon 库,一个是 RestSharp,分别用于 JSON 解析和 HTTP 请求处理,可是这两个库实在是设计得太好了,各种使用接口,各种抽象,没个两三天我都没法说完全理解了整个库的结构。
就是因为这些设计良好,完全遵循 OOP 原则,高度抽象的类库将 Mono 默认的 Trampolines 的配置耗尽了,所以捏,我们就把这个编译选项开大就好了,解决方案就是上面咱们提到的咯。
阅读(...) 评论()新手科普:
进阶攻略:
每周限免英雄(10月16日-10月22日)
版本热门英雄
新英雄介绍
王者荣耀游戏闪退怎么办 登录闪退解决方案公告
王者荣耀新闻导语
王者荣耀更新后闪退怎么办?王者荣耀更新后为什么会闪退?官方给出了解决办法,一起看看吧!
亲爱的召唤师:
欢迎来到王者荣耀!&无限荣耀&版本更新后,部分安卓平台的召唤师出现了登录闪退,当前问题已经定位,大家可以通过如下方式予以解决:
目前官网以及各大应用市场已经在陆续上传修复闪退的客户端(版本号:1.17.1.11),大家可以卸载手机中的已有客户端,前往官网主页以及各大应用市场下载安装修复后的客户端!
如安装新版本客户端后,还存在异常,欢迎大家通过各个渠道提交反馈。
手机看攻略,电脑玩游戏两不误!
加点再也不需要切来切去啦~
【王者荣耀】最新消息第一时间推送给您
二维码扫描
开发公司: 天美工作室
游戏类型: MOBA手游
代理公司: 腾讯
国服官网:
运营情况: 公测
专区编辑: 小溪
文明游戏,娱乐开黑,快速上分,成就最强王者为什么你的游戏总是卡顿闪退?腾讯解密unity游戏内存管理方法-牛人微信
为什么你的游戏总是卡顿闪退?腾讯解密unity游戏内存管理方法
本文由腾讯WeTest授权发布,作者hechun。
著作权归作者所有。商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。
内存是游戏的硬伤,如果没有做好内存的管理问题,游戏极有可能会出现卡顿,闪退等影响用户体验的现象。本文介绍了在腾讯游戏在Unity游戏开发过程中常见的Mono内存管理问题,并介绍了一系列解决的策略和方法。
什么是Mono内存对于目前绝大多数基于Unity引擎开发的项目而言,其托管堆内存是由Mono分配和管理的。“托管”的本意是Mono可以自动地改变堆的大小来适应你所需要的内存,并且适时地调用垃圾回收(GarbageCollection)操作来释放已经不需要的内存,从而降低开发人员在代码内存管理方面的门槛。Unity游戏在运行时的内存占用情况可以用下图表示:
目前绝大部分Unity游戏逻辑代码所使用的语言为C#,C#代码所占用的内存又称为mono内存,这是因为Unity是通过mono来跨平台解析并运行C#代码的,在Android系统上,游戏的lib目录下存在的libmono.so文件,就是mono在Android系统上的实现。C#代码通过mono解析执行,所需要的内存自然也是由mono来进行分配管理,下面就介绍一下mono的内存管理策略以及内存泄漏分析。 Mono内存管理策略Mono通过垃圾回收机制(GarbageCollect,简称GC)对内存进行管理。Mono内存分为两部分,已用内存(used)和堆内存(heap),已用内存指的是mono实际需要使用的内存,堆内存指的是mono向操作系统申请的内存,两者的差值就是mono的空闲内存。
当mono需要分配内存时,会先查看空闲内存是否足够,如果足够的话,直接在空闲内存中分配,否则mono会进行一次GC以释放更多的空闲内存,如果GC之后仍然没有足够的空闲内存,则mono会向操作系统申请内存,并扩充堆内存,具体如下图所示。
通过上文可知,GC的主要作用在于从已用内存中找出那些不再需要使用的内存,并进行释放。Mono中的GC主要有以下几个步骤:1.停止所有需要mono内存分配的线程。2.遍历所有已用内存,找到那些不再需要使用的内存,并进行标记。3.释放被标记的内存到空闲内存。4.重新开始被停止的线程。除了空闲内存不足时mono会自动调用GC外,也可以在代码中调用GC.Collect()手动进行GC,但是,GC本身是比较耗时的操作,而且由于GC会暂停那些需要mono内存分配的线程(C#代码创建的线程和主线程),因此无论是否在主线程中调用,GC都会导致游戏一定程度的卡顿,需要谨慎处理。另外,GC释放的内存只会留给mono使用,并不会交还给操作系统,因此mono堆内存是只增不减的。 Mono内存泄漏分析Mono是如何判断已用内存中哪些是不再需要使用的呢?是通过引用关系的方式来进行的。Mono会跟踪每次内存分配的动作,并维护一个分配对象表,当GC的时候,以全局数据区和当前寄存器中的对象为根节点,按照引用关系进行遍历,对于遍历到的每一个对象,将其标记为活的(alive)。
如上图所示,假设A是处于全局数据区的一个对象,那么在GC的时候将作为根节点进行遍历,由于B、C、D对象都可以由A遍历到,因此被标记为活的,E、F对象则没有被标记。注意,由于引用关系是单向的,A引用了B并不代表B也引用了A,所以遍历也只能单向进行。由于GC以全局数据区和当前寄存器中的对象为根节点进行遍历,所以对象的被标记意味着该对象可以通过全局对象或者当前上下文访问到,而没有被标记的对象则意味着该对象无法通过任何途径访问到,即该对象“失联”了,GC最终会将所有“失联”的对象内存进行回收,上图中的E和F将会在GC过程中被回收。既然mono已经有了完善的GC机制,那是否还会存在内存泄漏呢?答案是肯定的,只是此处的内存泄漏需要重新定义一下,我们把对象已经不再需要使用却没有被GC回收的情况称为mono内存泄漏。Mono内存泄漏会使空闲内存减少,GC频繁,mono堆不断扩充,最终导致游戏内存占用的升高。下图就是一个mono内存泄漏的例子。 解决办法对于mono内存泄漏,一般只能通过猜测+不断修改代码测试的方法来修复问题,效率很低,腾讯Wetest平台的Cube工具提供了mono内存快照对比的功能,并包括对象分配堆栈,对象引用关系等详细信息,是定位mono内存泄漏问题的一大利器。下面结合具体的代码尝试使用Cube定位mono内存泄漏问题。首先我们定义类A,并在A的构造函数中申请了一块int[1000]大小的内存。
接着我们定义A类型的静态变量objectA,在游戏界面上绘制一个按钮,并在按钮点击事件中给objectA赋值,此时新生成了newint[1000]对象,并由objectA引用。
使用Cube的mono内存检测功能,并在按钮按下之前和按下之后分别进行一次快照,对比两次快照,查看快照间新增对象。
可以看到,按钮按下前后新增的最大对象即为代码中生成的newint[1000]对象,并且该对象被引用的次数为1,为了查看详细的引用关系,下载快照文件snapshot2,其中有这样两行数据:
第一行说明在OnGUI函数中生成了一个A类型的对象,其指针为,第二行说明在OnGUI()-&A:.cotr()中生成了一个Int32[]类型的对象,并且该对象被指针为的对象引用。即newint[1000]对象被objectA引用,这也是导致newint[1000]对象无法被GC回收的原因。而objectA本身是一个静态对象,是GC的根节点,因此没有对象引用。如果需要生成的newint[1000]对象被回收怎么做呢?很简单,将objectA.a设置为null,没有了objectA对其的引用,自然会被GC回收了。需要说明的是,将objectA.a设置为null只是断绝了引用关系,真正对象的回收要等到GC的时候才会进行,Cube在获取内存快照的时候会首先进行一次GC,防止由于没有及时调用GC导致的误判。游戏中大部分mono内存泄漏的情况都是由于静态对象的引用引起的,因此对于静态对象的使用需要特别注意,尽量少用静态对象,对于不再需要的对象将其引用设置为null,使其可以被GC及时回收,但是由于游戏代码过于复杂,对象间的引用关系层层嵌套,真正操作起来难度很大。可以首先使用Cube工具进行分析,根据mono内存趋势找出泄漏的具体场景,然后再使用快照对比功能进行详细分析。 腾讯游戏品质管理团队专门打造的工具“Cube”目前已经可以使用,“Cube”可以帮助开发者发现Unity手游内分类资源的占用情况,尤其是对Unity游戏场景中的FPS、CPU、PSS的变化趋势重点关注,帮助在Unity游戏开发过程中不断改善玩家的体验。目前功能免费开放中。
↙点击“阅读原文”进入Cube功能页面(游戏原画教程库)
(tyrfenrir)
(老张家的飞飞)
第三方登录:手机微信游戏闪退怎么办
全部答案(共2个回答)
重装完玩游戏也是一样闪退
微信常见闪退原因: 一、文件损坏造成微信闪退遇到这个问题反复重新安装微信是解决不了问题,需要先清空微信数据然后重新安装才可以。按菜单键,找到系统设置-&应用程序...
我手机也是
软件闪退一般都是手机内存不足的表现,建议在打开微信之前,先清理下手机的内存,吧不用的后台都关闭了,为微信流出足够的空间。要是我的回答对你有帮助,记得设为好评哦
给你闪退的软件卸载了 然后去itunes里面重新下载就好了
亲。如果我的回答对你有帮助。记得给个好评哦。谢谢!
答: 雅士利奶粉没吃完过期了怎么办?有遇到过这种问题怎样处理的?
答: 美国苹果公司的新款手机,全触屏的智能机,在中国卖的很贵。
答: 手机购买还是找正规卖家
天猫等网站
答: 可能被设置了禁言你IP接入吧
大家还关注
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区
相关问答:123456789101112131415}

我要回帖

更多关于 微信登录闪退 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信