如何在Unity中检测死循环和卡死

当游戏在手机/模拟器上卡死,logcat没有日志输出,也没有卡死堆栈信息或者bugly也没有捕获到异常,你是否很焦急?本文介绍一下我们项目中检测Unity卡死的方法,也许适合你使用。

实现原理

在绝大多数情况下我们可以认为Unity是单线程的,基于这点我们在Unity的系统函数FixedUpdate中统计游戏运行期间的总帧数,如果Unity没有卡死,那么TotalFrame是会一直累加的,如果在某一段时间内TotalFrame都不会变化了,则可以认为Unity已经卡死了

既然Unity的主线程已经卡死了,我们就需要用另一个线程用来定时检查unity主线程中的TotalFrame是否不会变化了

示例代码

using System;
using System.Threading;
using UnityEngine;

namespace KEngine
{
 /// <summary>
 /// 开另外一个线程检测unity是否被卡死
 /// </summary>
 public static class UnityThreadDetect
 {
  public static Thread _MainThread = System.Threading.Thread.CurrentThread;//获取unity线程
  private static int check_interval = 3000;//检测间隔

  public static void Start()
  {
   new Thread(CheckMainThread).Start();
  }

  static void CheckMainThread()
  {
   long frame = 0;
   while(!AppEngine.IsApplicationQuit)
   {
    frame = AppEngine.TotalFrame;
    Thread.Sleep(check_interval);
    if (frame == AppEngine.TotalFrame)
    {
     Log.LogToFile("unity thread dead,ThreadState:{0}",_MainThread.ThreadState);
     if (AppEngine.IsApplicationFocus)
     {
      //todo report error
     }
    }
   }
  }
 }
}

捕获卡死的方法名

在我们的游戏中一般出现卡死的情况都是在定时器里面,我们的定时器是通过在Unity的Update驱动定时器列表,当卡死时,在另一个线程中打印出定时器中正在执行的函数就可以定位到卡死的函数了。定时器可参考:UnityTimer中的Timer.cs

同时在Unity的Update进行派发多个事件,比如PreUpdate,Update,以便出问题更容易定位到卡在那儿

举例说明问题

下面举例我们遇到的出现卡死的问题

死循环

下面这个死循环在Unity中会卡死,而在.NET中不会,.NET中当i超过byte的最大值255时i会从0开始

public static void TesBadCode()
{
	byte i = 0;
	while (true)
	{
		i++;
	}
}

目前我们遇到的绝大多数情况都是逻辑代码中写了where(true) do xxx 然后里面某些情况不会break,导致循环永远退不出来

屏蔽了事件系统

在某些系统中屏蔽掉了UGUI的事件系统,导致无法接受用户输入,这个问题不应该归类为Unity卡死,但用户反馈来看就是卡死了,无法操作。

重复添加定时器

起因是底层没有对同名定时器进行限制,在某些逻辑中误使用,出现每秒添加一个定时器,而定时器中的逻辑很大且长时间不退出的,当不断添加重复定时器就导致游戏运行越来越慢

重复注册事件

在一些界面的刷新函数和控制器函数,被频繁重复注册了事件,导致在抛出事件时,同一个函数被调用了N次,这个问题在Unity的Profiler中可以清晰看到函数的调用次数

扩展

递归调用

递归调用,会报stack overflow,不会让unity卡死

为什么无限循环递归调用不会卡死Unity?

这是因为每个方法的方法调用栈容量是有限的,当超出之后就会跳出报stack overflow,不会让应用程序卡死

public static void TesBadCode()
{
	while (true)
	{
		TesBadCode();
	}
}

总结

到此这篇关于在Unity中检测死循环和卡死的文章就介绍到这了,更多相关Unity检测死循环和卡死内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • unity实现透明水波纹扭曲

    本文实例为大家分享了unity实现透明水波纹扭曲的具体代码,供大家参考,具体内容如下 需要挂一个摄像机把脚本挂在一个物体上 可随意在物体上面点击 shader: Shader "Unlit/Water" { Properties { _MainTex ("Texture", 2D) = "white" {} _WaterUV("WaterUV",2D)="while"{} _WaterIntensity(&

  • Unity3D实现摄像机镜头移动并限制角度

    本文实例为大家分享了Unity3D实现摄像机镜头移动并限制角度的具体代码,供大家参考,具体内容如下 摄像机镜头跟随鼠标移动,并限制上下左右的移动角度 public class ViewFromCream : MonoBehaviour { public int speed=5; public Vector3 vect; private float xcream; private float ycream; public void Update() { CreamView(); } private

  • Unity Shader实现裁切效果

    Unity Shader学习:裁切效果,供大家参考,具体内容如下 之前看到有人问关于物体裁切方面的问题,初学shader的话可能搞得不是很明白,这里提供下比较简单的思路,有需要的话可以直接使用.(关于切面缝合还没有找到比较好的方法) 裁切原理:将世界空间中像素y值(垂直裁切)大于物体自身坐标y值一定范围的直接discard. c#部分: using System.Collections; using System.Collections.Generic; using UnityEngine; p

  • Unity Shader实现水波纹效果

    本文实例为大家分享了Unity Shader实现水波纹的具体代码,供大家参考,具体内容如下 效果: Shader代码: Shader "Custom/shuibowen"{ Properties{ _MainTex("Base (RGB)",2D)="white"{} _distanceFactor("Distancefactor",float)=1 _timeFactor("time factor",fl

  • Unity3D Shader实现镜子效果

    本文实例为大家分享了Unity3D Shader实现镜子效果的具体代码,供大家参考,具体内容如下/p> Shader部分代码: Shader "Custom/FanShe" { Properties{ _MainTex("Albedo",2D) = "white"{} _MainTint("Diffuse Color",Color)=(1,1,1,1) _Cubemap("Cubemap",CUBE)

  • 如何在Unity中检测死循环和卡死

    当游戏在手机/模拟器上卡死,logcat没有日志输出,也没有卡死堆栈信息或者bugly也没有捕获到异常,你是否很焦急?本文介绍一下我们项目中检测Unity卡死的方法,也许适合你使用. 实现原理 在绝大多数情况下我们可以认为Unity是单线程的,基于这点我们在Unity的系统函数FixedUpdate中统计游戏运行期间的总帧数,如果Unity没有卡死,那么TotalFrame是会一直累加的,如果在某一段时间内TotalFrame都不会变化了,则可以认为Unity已经卡死了 既然Unity的主线程已

  • 如何在Unity中使用VR暴风魔镜蓝牙手柄

    目录 一.蓝牙手柄按键的响应 二.UGUI的事件检测 一.蓝牙手柄按键的响应 在暴风魔镜的官网下载了最新的SDK后导入Unity项目,发现SDK中的DEMO全部是非手柄控制的,然后只能参照着SDK里面的接口说明文档自己研究~~结果发现接口文档非一般的坑,一开始是直接在MojingInputManager.cs里面直接填充,直到最后才发现用IntegrateInputManager.prefab替换场景中原有的MojingInputManager.prefab以后就可以跟检测Unity的输入一样检

  • 如何检测JavaScript中的死循环示例详解

    前言 如果我们需要执行用户写的代码,如和避免死循环?我们最近遇到了这个问题,因为写错代码很常见,所以我们进行了一下尝试. 首先我们需要使用iframe 这主要是安全考虑,我们需要一个sandbox环境来执行JavaScript,避免影响到整体.iframe的sandbox属性可以用来禁止弹窗等等,非常有用. 地址可以选择Blob url,不过blob url会持有当前web page的origin,如果用户拷贝一些乱七八糟的代码不小心执行的话,会有安全问题.所以最终决定用data URI. if

  • 如何在vue中使用ts的示例代码

    本文介绍了如何在vue中使用ts的示例代码,分享给大家,具体如下: 注意:此文并不是把vue改为全部替换为ts,而是可以在原来的项目中植入ts文件,目前只是实践阶段,向ts转化过程中的过渡. ts有什么用? 类型检查.直接编译到原生js.引入新的语法糖 为什么用ts? TypeScript的设计目的应该是解决JavaScript的"痛点":弱类型和没有命名空间,导致很难模块化,不适合开发大型程序.另外它还提供了一些语法糖来帮助大家更方便地实践面向对象的编程. typescript不仅可

  • 如何在PHP中读写文件

    在PHP中读写文件,可以用到一下内置函数: 1.fopen(创建文件和打开文件) 语法: fopen(filename,mode) filename,规定要打开的文件.mode,打开文件的模式,可能的值见下表. mode 说明 "r" 只读方式打开,将文件指针指向文件开头. "r+" 读写方式打开,将文件指针指向文件开头. "w" 写入方式打开,将文件指针指向文件开头并将文件大小截为零.如果文件不存在则尝试创建. "w+" 读

  • 详解如何在pyqt中通过OpenCV实现对窗口的透视变换

    窗口的透视变换效果    当我们点击Win10的UWP应用中的小部件时,会发现小部件会朝着鼠标点击位置凹陷下去,而且不同的点击位置对应着不同的凹陷情况,看起来就好像小部件在屏幕上不只有x轴和y轴,甚至还有一个z轴.要做到这一点,其实只要对窗口进行透视变换即可.下面是对Qt的窗口和按钮进行透视变换的效果: 具体代码    1.下面先定义一个类,它的作用是将传入的 QPixmap 转换为numpy 数组,然后用 opencv 的 warpPerspective 对数组进行透视变换,最后再将 nump

  • 如何在IOS中使用IBeacon

    什么是iBeacon? iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能.其工作方式是,配备有低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的 ID,接收到该 ID 的应用软件会根据该 ID 采取一些行动. 从个人的角度看: iBeacon向四面八方不停地广播信号,就像是往平静的水面上扔了一块石子,泛起层层涟漪(俗称水波),波峰相当于 iBeacon 的RSSI(接受信号强度指示),越靠近中心点的地方波峰越高(RSSI 越大),这个波峰的

  • 详解Unity地面检测方案

    1.普通射线 在角色坐标(一般是脚底),发射一根向下的射线(长度约0.2) 但是简单射线只适用于简单地形,实际使用中常常遇到以下问题 1.用collider去碰撞地面,某些时候会有一定的穿插,于是角色的最低点就可能穿透地面,你发射射线的点可能就到了地面以下,射线一直检测不到真正的地面,于是角色就一直悬空 2.角色走斜坡时,角色中点可能会离开地面一小段距离,这一小段距离往往就足够让判断机制误以为角色已经离地,如果你增加射线的长度,那么一定程度上能缓解斜坡问题,但是会降低跳跃判断的精度,精度过低就有

  • 如何在MyBatis中实现DataSource

    一.DataSource 首先大家要清楚DataSource属于MyBatis三层架构设计的基础层    然后我们来看看具体的实现. 在数据持久层中,数据源是一个非常重要的组件,其性能直接关系到整个数据持久层的性能,在实际开发中我们常用的数据源有 Apache Common DBCP,C3P0,Druid 等,MyBatis不仅可以集成第三方数据源,还提供的有自己实现的数据源. 在MyBatis中提供了两个 javax.sql.DataSource 接口的实现,分别是 PooledDataSou

  • 如何在AngularJs中调用第三方插件库

    在AngularJs中我们会不可避免的使用第三方库,例如jquery插件库.我们不能散乱的在AngularJS中引入这些库,例如在controller中.那么应该怎么在Angular中使用第三方库呢? 如何使用? 很简单,给插件写一个directive. 在这里,我会使用一个简单的jquery插件Toolbar.js 的DEMO. 这是我们如何在jquery中创建一个tooltip的: <!-- Click this to see a toolbar --> <div id="

随机推荐