hi,
这边发现 gc.IncrementalBeginDestroyEnabled 打开时,会出现崩溃(外网出现,概率比较小)。关掉时正常
捋了以下逻辑,有可能是UStaticMeshComponent与UStaticMesh的BeginDestory的顺序可能导致崩溃,以下是分析
- UStaticMeshComponent的渲染代理对象FStaticMeshSceneProxy,要使用UStaticMesh的渲染资源(TUniquePtr<class FStaticMeshRenderData> UStaticMesh::RenderData的成员)去渲染。所以要保证FStaticMeshSceneProxy对象存在时,渲染资产也要存在
- UStaticMeshComponent的渲染代理对象FStaticMeshSceneProxy是在BeginDestory时尝试进行释放(UActorComponent::BeginDestroy() --> UActorComponent::ExecuteUnregisterEvents() --> UActorComponent::DestroyRenderState_Concurrent() --> UPrimitiveComponent::DestroyRenderState_Concurrent()),下一帧在render线程就会进行释放
- UStaticMesh的渲染资产是在 UStaticMesh::BeginDestroy() 中尝试进行释放 UStaticMesh::ReleaseResources() --> FStaticMeshRenderData::ReleaseResources() ,下一帧在render线程就会进行释放
- 如果遇到 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()
}
}