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

作者:Qing''s Blog 时间:2023-12-18 00:55:17 

当游戏在手机/模拟器上卡死,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();
}
}

来源:https://www.cnblogs.com/zhaoqingqing/p/13556058.html

标签:Unity,死循环,卡死
0
投稿

猜你喜欢

  • Java中两种基本的输入方式小结

    2023-02-06 18:37:24
  • 关于weblogic部署Java项目的包冲突问题的解决

    2023-07-19 19:02:59
  • Android开发:浅谈MVP模式应用与内存泄漏问题解决

    2023-05-01 20:42:43
  • Android 自定义View实现多节点进度条功能

    2022-05-04 17:13:37
  • Entity Framework映射TPH、TPT、TPC与继承类

    2022-10-18 04:52:52
  • Java中的static关键字深入理解

    2022-02-01 12:59:40
  • 了解Java虚拟机JVM的基本结构及JVM的内存溢出方式

    2023-02-20 03:08:51
  • C#根据前台传入实体名称实现动态查询数据

    2021-06-17 09:28:43
  • 如何从UA分辨出Android设备类型

    2023-09-03 00:37:44
  • C# 拼图魔方小游戏

    2023-10-27 20:41:22
  • Java面试题冲刺第十八天--Spring框架3

    2023-04-17 22:44:29
  • SpringMVC实现文件上传与下载、拦截器、异常处理器等功能

    2023-07-21 19:18:44
  • C#中事件处理的个人体会

    2023-11-02 02:14:39
  • Spring Cloud Gateway整合sentinel 实现流控熔断的问题

    2022-01-18 23:10:05
  • java_object的简单使用详解

    2023-08-22 11:35:57
  • Java实现二叉树的深度优先遍历和广度优先遍历算法示例

    2021-07-16 12:37:17
  • Mybatis参数传递示例代码

    2023-05-20 09:43:08
  • Java读写文件,在文件中搜索内容,并输出含有该内容的所有行方式

    2022-12-14 18:23:58
  • Java执行cmd命令两种实现方法解析

    2022-09-24 02:43:49
  • Android实现图片轮播效果

    2022-01-24 02:33:13
  • asp之家 软件编程 m.aspxhome.com