UE4 Editor ClearLog Crash

UE4 4.24.3版本,编辑器Output Log窗口中,右键--Clear Log操作很大概率会导致编辑器奔溃;
解决办法:

相关文件:

Engine\Source\Developer\OutputLog\Private\SOutputLog.cpp
Engine\Source\Developer\OutputLog\Private\SOutputLog.h

SOutputLog.h文件中添加:

bool bNeedClearLog;
void DoClearLog();

 SOutputLog.cpp文件修改:

void SOutputLog::Construct( const FArguments& InArgs ){
        ...
        bNeedClearLog = false;
}
void SOutputLog::OnClearLog()
{
    bNeedClearLog = true;
}

void SOutputLog::DoClearLog() {
    if (bNeedClearLog)
    {
        // Make sure the cursor is back at the start of the log before we clear it
        MessagesTextBox->GoTo(FTextLocation(0));

        MessagesTextMarshaller->ClearMessages();
        MessagesTextBox->Refresh();
        bIsUserScrolled = false;
        bNeedClearLog = false;
    }
}

void SOutputLog::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
    DoClearLog();
        ...
}

分析:

先前的实际Clear代码是在OnClearLog()函数中调用的,这个函数应该是在鼠标点击事件调用栈中执行的;

将实际Clear代码移动到DoClearLog()函数中,并在Tick()函数中调用,也就是移动到渲染循环中执行;

通过bNeedClearLog标识,Tick中是否需要执行真正的Clear操作;
这些改动,在实际测试中证实能够避免ClearLog操作导致Editor奔溃

 

猜测原因:
之前会奔溃,猜测是鼠标事件调用和渲染不是在同一个线程中,而Clear操作,实际上在清理Log列表(一个TArray对象),会比较耗时;
另外,在Editor中可以观察到,当ClearLog所在的ContentMenu打开时,Eidtor World是处于暂停状态的,点击ClearLog,ContentMenu立即关闭,Eidtor World恢复运行状态;

这里面不知道有没有调用先后关系的问题,只能等以后对Slate框架源码有更多的认识才能知道;

 

#2020/9/8更新
今天在UE4 QQ群里面有讨论ClearLog导致Editor崩溃的问题,有人提到,奔溃原因是输入发导致;
目前使用的是Windows10自带的微软拼音输入法,在语言栏的设置中,打开输入设置界面,关闭里面的所有开关后,同样的操作Editor确实不再崩溃了
具体是那个输入法功能导致的Editor奔溃没有一一测试;

因为没有安装其他常用输入法,就没有一一测试了;

有需要的可以尝试关闭一些输入法功能试试看;

#2020/12/17更新

距离上次更新好长一段时间了

期间一直在忍受ClearLog奔溃的问题;9/8号更新的方法:调整输入法设置并不起多大作用,或者根本不起作用吧!这个奔溃问题本来也是有概率出现的bug;

前面的操作思路是把Clear动作跳过鼠标点击回调,延迟到tick中执行;
这几天稍微改动一下,基本思路是往后延迟几帧再执行Clear动作;

添加一个帧计数:

SOutputLog.h头文件中添加:

int frameCount;

 SOutputLog.cpp文件修改:

void SOutputLog::OnClearLog()
{
    bNeedClearLog = true;
    frameCount = 3;
}

void SOutputLog::DoClearLog() 
{
    if (frameCount > 0)
    {
        frameCount--;
    }
    else 
    {
        if (bNeedClearLog)
        {
            // Make sure the cursor is back at the start of the log before we clear it
            MessagesTextBox->GoTo(FTextLocation(0));

            MessagesTextMarshaller->ClearMessages();
            MessagesTextBox->Refresh();
            bIsUserScrolled = false;
            bNeedClearLog = false;
        }
    }
}

不同工程尝试过几次,貌似有效;至于是不是没碰到概率事件让时间来验证;