欢迎光临散文网 会员登陆 & 注册

遇上UE4/UE5崩溃和卡机的问题该如何处理呢?

2022-11-29 16:41 作者:渲云渲染平台  | 我要投稿


不少朋友在使用UE4/UE5时,都有遇到崩溃和卡机的问题,大数情况下,可能都不知如何解决,渲云小编来分析了一些经验技巧,该如何解决呢?具体来看下面的介绍操作。


一、常规崩溃定位

当游戏崩溃时,开发者必须想要定位哪一行代码崩溃了,以及崩溃发生时内存是什么。在错觉引擎中,这项工作是由引擎自动完成的。引擎会将崩溃的转储文件保存在Saved/ crash下。编辑器的位置。


游戏包在运行时的位置是相似的。PC版本在游戏目录下,Android版本在Android/data/(游戏包名)/下,iOS版本在应用对应的Documents目录下。当出现多次崩溃时,可以按修改日期排序,找到最新的一次。


打开后你可以看到很多信息。

Dmp文件:文件崩溃的转储信息。您可以直接将文件拖到visual studio,它将自动跳转到崩溃站点的代码行。


Log文件:该文件是崩溃时的日志信息。您可以根据打印的日志做出一些崩溃辅助判断。例如,在崩溃之前执行了哪些关键操作。


runtime-xml文件:该文件以文本形式记录崩溃场景,包括堆栈、崩溃代码等。它本质上类似于dmp文件,因为dmp是一个不可读的二进制文件。当手边没有符号文件时,可以使用该文件分析崩溃。

在理解了引擎的这一功能后,可以定位80%的碰撞。就像最常见的Signal 11一样,我们可以初步找到场景的位置。


二、卡死检测


有时根据坠机现场很难找出坠机的原因。我们希望在一些关键位置输出堆栈或内存信息。或者它不一定是崩溃,而是一个无休止的循环卡住了,所以一定没有如上所述的转储信息输出。引擎连接到Lua或其他脚本语言。当脚本出现异常时,您还必须希望输出c++堆栈。因此,我绝对希望我能找到一些方法在代码中输出当前堆栈。该引擎也提供了这样的方法。参见StackWalk类


有一系列的函数。例如,可以使用StackWalkAndDump函数将当前堆栈输出为字符串。当然,如果它不是GameThread,这个类也为转储指定的线程提供一个堆栈。例如,lua脚本中的代码崩溃,但由于lua的崩溃有一个通用函数,c++不会直接崩溃。我们可以手动调用这样的函数,将c++堆栈写入Log。


为了解决业务问题,虚幻引擎还封装了一个单独的守护进程线程ThreadHeartBeat。当检测到线程的心跳超过时间限制时,还会在内部调用上面的函数,将卡住的线程堆栈输出到Log中。

自己的业务也可以根据上述实践进行封装。该功能默认关闭。毕竟,有额外线程的成本。项目需要使用USE_ HANG_ The DETECTION宏打开。


三、内存随机损坏或泄漏

内存损坏和随机程序崩溃问题是大多数项目中最麻烦的问题。事实上,虚幻的底层还提供了一些定位代码来解决这些问题。因为这是一个内存问题,所以这些工具代码也适用于内存。


在全局重载的c++中,illusion本身有new和delete。当业务分配和释放内存时,实际上会调用引擎的FMemory类中的Malloc和Free。引擎会根据情况从内存池中获取内存。引擎使用内存池本身的内存根据定时向系统请求内存。如果你使用引擎的LLM来计算内存,你应该知道LLM有两个跟踪器,默认和平台。这两个维度还对应于两种情况:业务需要来自引擎的内存,而引擎需要来自操作系统的内存。

LLM Default和LLM Platform的关系如下图所示。由于这种机制,我们总是说UE4/UE5项目不使用STL。因为STL有自己的分配器,当没有指定分配器时,所有的内存分配都不由引擎管理,而且因为STL本身只有头文件,即使显式指定了分配器,在跨dll使用时可能会由于疏忽而导致一些内存问题。


这里的关键点是FMemory可以在内部使用多个分配器,而且有些分配器可以嵌套,这对上层业务不敏感。引擎通常默认使用binne2或Binned3,内部内存池将根据大小制作。当内存池不足时,每次向系统应用固定大小的Chunk。由于本文的重点不是内存管理和LLM,因此不进行扩展。


要检查内存损坏,需要在这里打开一些特殊的分配器。最常用的有以下几种:

Ansi:这是一个标准的分配器,这意味着UE4不使用任何额外的内存管理,而是直接使用平台的本机new和delete。有时它需要使用一些平台的内存工具。这个模式很好。例如,在iOS平台上,需要检查内存泄漏。如果你使用默认的binne2 /Binned3,你不能用Xcode的内置工具找到泄漏的具体代码。您所看到的就是正在申请内存池,并且当您驱动到Ansi时,您可以定位内存泄漏字段。


Stomp:这是引擎提供的检查内存损坏的强大工具。一般情况下,启用该模式。崩溃的第一个场景是编写代码的位置。具体原理是利用操作系统的虚拟地址概念。我们知道,当我们向系统请求内存时,我们得到的指针实际上是一个虚拟地址。是否真正分配了物理内存取决于具体情况。如何解决这些问题,请参考下面的说明

在这种模式下,每次内存分配的指针地址只会增加,而不会减少。实际使用的内存将要求系统分配相应的物理内存。当需要释放已使用的内存时,只取消虚拟地址与物理内存的映射关系,相应的虚拟地址不会被回收。因为这些操作非常特殊,所以不能直接使用malloc等函数从系统请求内存。Windows使用VirtualAlloc函数,其他平台使用mmap函数。回收时,Windows使用VirtualFree,其他平台使用munmap功能。


随机崩溃的内存写失败基本上是因为崩溃时间不是第一个场景。在正常模式下,第一个场景有很大概率是正常内存,因为内存本身是合法的,不会塌缩,但是正常内存中的数据写的不好。在Stomp模式下,地址只会增加而不会减少,也不会被重用。只要写入不应该写入的内存,比如那些在回收后只有虚拟地址的指针,就会在第一时间崩溃。UE5还提供了在运行时可以通过命令行stomp2malloc打开Stomp2。


PoisonProxy:这个模式,顾名思义,用毒药涂抹内存。它主要解决不使用未初始化或空闲内存的问题,如下面的说明所述。

其原理是在分配或释放后,通过Memset将以下魔法代码填满内存

老程序员应该对0xcd、0xcc和0xdd的值印象深刻。毕竟,Windows也做同样的事情。一堆0xcccc的GBK Chinese很热,0xcdcd的GBK Chinese也很热。当崩溃发生时,将显示这样的地址。你可以根据0xcc和0xcd来判断释放的内存是否没有初始化或被使用,这样你就可以定位代码出现问题的第一个场景。

ReplayProxy:用来记录分配给文件的内存。有时检查一些性能问题可能是有用的。

当然,除此之外,您还可以使用一些外部工具来检查内存问题,比如最常用的ASan。


四、减少由野指针引起的崩溃的技巧

当引擎判断UObject是否合法时,它提供了基于编程经验或指针特征来检测野指针的想法,我们也可以参考,例如IsValidLowLevelFast。


你可以看到上面三个if的代码非常有趣。如果这是一个合法的对象,那么指针不能为空ptr或小于0x100,指针值必须是8的倍数,并且指针,即虚函数表,不能为空ptr。仔细想想,普通Object对象的指针确实需要满足这些条件。小于0x100的指针通常在系统内部使用。系统按照字节对齐的方式分配内存,所以它必须是8的倍数。经过这样的经验,基本排除了超过七分之八的野指针,所以我也建议将这种判断方法扩展到业务上使用。


渲云影视动画支持maya、3ds max 、C4D、Houdini、Clarisse、Katana、Keyshot、Blender、Vred等。以UE渲染来说,高量高速,海量GPU资源,目前渲云平台是业内独家支持UE渲染。渲染过程中,支持实时预览。


解决由于本地配置不足引起的UE渲染慢和渲染卡顿等问题,速度更快,效率更高。

海量GPU资源

强大的公有云资源配置,GPU节点弹性扩展,服务器规格灵活调配,可一键加载各种渲染环境,满足各种渲染任务执行。


遇上UE4/UE5崩溃和卡机的问题该如何处理呢?的评论 (共 条)

分享到微博请遵守国家法律