【GC】UStaticMeshComponent与StaticMesh BeginDestory的流程

hi,

这边发现 gc.IncrementalBeginDestroyEnabled 打开时,会出现崩溃(外网出现,概率比较小)。关掉时正常

捋了以下逻辑,有可能是UStaticMeshComponent与UStaticMesh的BeginDestory的顺序可能导致崩溃,以下是分析

  1. UStaticMeshComponent的渲染代理对象FStaticMeshSceneProxy,要使用UStaticMesh的渲染资源(TUniquePtr<class FStaticMeshRenderData> UStaticMesh::RenderData的成员)去渲染。所以要保证FStaticMeshSceneProxy对象存在时,渲染资产也要存在
  2. UStaticMeshComponent的渲染代理对象FStaticMeshSceneProxy是在BeginDestory时尝试进行释放(UActorComponent::BeginDestroy() --> UActorComponent::ExecuteUnregisterEvents() --> UActorComponent::DestroyRenderState_Concurrent() --> UPrimitiveComponent::DestroyRenderState_Concurrent()),下一帧在render线程就会进行释放
  3. UStaticMesh的渲染资产是在 UStaticMesh::BeginDestroy() 中尝试进行释放 UStaticMesh::ReleaseResources() --> FStaticMeshRenderData::ReleaseResources() ,下一帧在render线程就会进行释放
  4. 如果遇到 UStaticMesh::BeginDestroy() 已经调用了 UStaticMesh::ReleaseResources(),但是由于 gc.IncrementalBeginDestroyEnabled 打开,导致多帧以内 UStaticMeshComponent::BeginDestroy() 还没有调用,就有可能 FStaticMeshSceneProxy 还在使用一个已经析构的资源在渲染,从而导致崩溃

如果以上4点成立的话,修复方法是不是可以改成不在BeginDestroy()中释放资源,延迟到 UStaticMesh::IsReadyForFinishDestroy() 进行释放,因为GC可以保证,在所有对象的BeginDestroy()调用完后,才会开始调用 IsReadyForFinishDestroy() 的逻辑。同样,USkeletalMesh&USkinnedMeshComponent 也是类似

void UStaticMesh::BeginDestroy()
{
	Super::BeginDestroy();

	if (!HasPendingInitOrStreaming() && bRenderingResourcesInitialized)
	{
		//ReleaseResources(); //资源释放不在BeginDestroy()中,延迟到UStaticMesh::IsReadyForFinishDestroy()
	}
}



Hi,

感谢反馈,很抱歉,我的确没有看出来我们有什么机制可以保证不出现你说的问题,但是如果这的确是一个bug,貌似又很少有人反馈过…我已经在跟同事沟通了,如果有结论,我会再在这里更新。

Hi,

我们有可能也遇到了类似的问题,能提供一下你看到的崩溃的call stack和log吗?

堆栈如下[Image Removed]log只有一部分,外网上报的大小有限

感谢,如果后续我们有进展,我也尽量在这里更新。