服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 如何在Unity中检测死循环和卡死

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

2022-10-08 15:34Qing''''s Blog C#

这篇文章主要介绍了在Unity中检测死循环和卡死的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

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

实现原理

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

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

示例代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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开始

?
1
2
3
4
5
6
7
8
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,不会让应用程序卡死

?
1
2
3
4
5
6
7
public static void TesBadCode()
{
    while (true)
    {
        TesBadCode();
    }
}

总结

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

原文链接:https://www.cnblogs.com/zhaoqingqing/p/13556058.html

延伸 · 阅读

精彩推荐
  • C#详解C#实现MD5加密的示例代码

    详解C#实现MD5加密的示例代码

    本篇文章主要介绍了C#实现MD5加密的示例代码,详细的介绍了几种方法,具有一定的参考价值,有兴趣的可以了解一下。...

    shenghui1884602021-12-16
  • C#C#编程实现发送邮件的方法(可添加附件)

    C#编程实现发送邮件的方法(可添加附件)

    这篇文章主要介绍了C#编程实现发送邮件的方法,具备添加附件的功能,涉及C#文件传输及邮件发送的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    期待秋天的叶8992021-11-05
  • C#C# 设计模式系列教程-模板方法模式

    C# 设计模式系列教程-模板方法模式

    模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码,子类实现算法的某些细节,有助于算法的扩展。...

    Wang Juqiang9052021-11-23
  • C#C# winform实现登陆次数限制

    C# winform实现登陆次数限制

    这篇文章主要介绍了C# winform实现登陆次数限制,相信大家都遇到过网站在用户多次输错密码之后会自动把账户冻结的情况,这种功能如何实现,下面小编为...

    net小伙10662021-11-21
  • C#C# 7.2中结构体性能问题的解决方案

    C# 7.2中结构体性能问题的解决方案

    这篇文章主要给大家介绍了关于C# 7.2中结构体性能问题的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    无明10892022-02-27
  • C#C#简单生成随机密码的方法示例

    C#简单生成随机密码的方法示例

    这篇文章主要介绍了C#简单生成随机密码的方法,结合具体实例形式分析了C#生成随机密码操作的前台界面与后台处理技巧,需要的朋友可以参考下...

    zhangsiyan6292022-01-10
  • C#C#利用GDI+给图片添加文字(文字自适应矩形区域)

    C#利用GDI+给图片添加文字(文字自适应矩形区域)

    这篇文章主要给大家介绍了关于C#利用GDI+给图片添加文字(文字自适应矩形区域)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作...

    Dandelion_drq12022022-02-22
  • C#C#中的事务用法实例分析

    C#中的事务用法实例分析

    这篇文章主要介绍了C#中的事务用法,以一个简单实例形式分析了C#创建及使用事物的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    yenange12272021-10-27