Crashes due to TypeClass objects getting garbage collected after loading a new world
Hello,
first off, important to note is that this issue only happens in packaged builds. We tried forcing it in PIE or standalone mode, but it wont happen.
Our HUD uses the <noesis:Brush.Shader /> extension to load in UE materials. Also, there are DataEventTriggers hooked up with UE events on the view model of the HUD for triggering storyboard animations.
When a transition to new level happens, Player controller and HUD get recreated and the game crashes for two possible reasons:
1) UMaterialInterface pointers stored in 'MaterialMap' and the NoesisTypClass objects in NoesisTypeClass.cpp were no longer valid.
2) The UFunction pointer attached to UObject::StaticClass() in NoesisTypeClass.cpp, line 2497 was no longer valid. Executing the event crashed the game
'USomeRandomComponent::FAction_DelegateWrapper' can be anything, as this is were the data is messed up.
To further verify that those objects were in fact garbage-collected, we placed breakpoints in various functions within NoesisTypeClass.cpp shortly before the crash happened.
MaterialMap was filled with garbage data and the functions added to UObject::StaticClass() as well.
Is this a known issue or are we doing something wrong here, for example in terms of object ownership?
As a temporary workaround to these issues we added a small gameinstance subsystem for keeping counted references of material and UFunction objects.
We think the way objects are currently cached without the UPROPERTY() specifier in NoesisTypeClass.cpp should be reworked, as it is extremely risky. Also, there is no point
where MaterialMap data gets removed, except when the Noesis Module is unloaded.
first off, important to note is that this issue only happens in packaged builds. We tried forcing it in PIE or standalone mode, but it wont happen.
Our HUD uses the <noesis:Brush.Shader /> extension to load in UE materials. Also, there are DataEventTriggers hooked up with UE events on the view model of the HUD for triggering storyboard animations.
When a transition to new level happens, Player controller and HUD get recreated and the game crashes for two possible reasons:
1) UMaterialInterface pointers stored in 'MaterialMap' and the NoesisTypClass objects in NoesisTypeClass.cpp were no longer valid.
Code: Select all
FD3D12CommandContextBase::RHIBeginDrawingViewport(FRHIViewport *,FRHITexture *) D3D12Viewport.cpp:876
CallbackCreateMaterialWrapper(Symbol) NoesisTypeClass.cpp:2848
<unknown> 0x00007ffcc9323ac8
...
<unknown> 0x00007ffcc940751e
UNoesisXaml::LoadXaml() NoesisXaml.cpp:33
UNoesisInstance::InitInstance() NoesisInstance.cpp:499
UNoesisInstance::NativeConstruct() NoesisInstance.cpp:1746
UNoesisInstance::OnWidgetRebuilt() NoesisInstance.cpp:1163
UWidget::TakeWidget_Private(TFunctionRef<TSharedPtr<SObjectWidget,1> __cdecl(UUserWidget *,TSharedRef<SWidget,1>)>) Widget.cpp:997
...
Code: Select all
[Inlined] operator&(EFunctionFlags,EFunctionFlags) Script.h:173
[Inlined] UFunction::HasAnyFunctionFlags(EFunctionFlags) Class.h:1832
UObject::ProcessEvent(UFunction *,void *) ScriptCore.cpp:2055
[Inlined] TScriptDelegate<FWeakObjectPtr>::ProcessDelegate(void *) ScriptDelegates.h:289
TMulticastScriptDelegate<FWeakObjectPtr>::ProcessMulticastDelegate<UObject>(void *) ScriptDelegates.h:579
USomeRandomComponent::FAction_Delegate(const TMulticastScriptDelegate<FWeakObjectPtr> &) USomeRandomComponent.gen.cpp:106
UViewModel_HUD::PlayShowAnimation() UViewModel_HUD.cpp:63
...
To further verify that those objects were in fact garbage-collected, we placed breakpoints in various functions within NoesisTypeClass.cpp shortly before the crash happened.
MaterialMap was filled with garbage data and the functions added to UObject::StaticClass() as well.
Is this a known issue or are we doing something wrong here, for example in terms of object ownership?
As a temporary workaround to these issues we added a small gameinstance subsystem for keeping counted references of material and UFunction objects.
We think the way objects are currently cached without the UPROPERTY() specifier in NoesisTypeClass.cpp should be reworked, as it is extremely risky. Also, there is no point
where MaterialMap data gets removed, except when the Noesis Module is unloaded.
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Hi vmaurer,
The problem with the UFunctions is solved by adding them to the root set when they are created. Right after add
I have created a ticket for the other issue: https://www.noesisengine.com/bugs/view.php?id=2641
I have to try to reproduce it, but I have a theory perhaps you can confirm: I think what's happening is that the same MaterialInterface is used by both the old and the new levels, but during the transition the old one is garbage collected and a new one is created at a different address. Our NoesisTypeClasses contain the pointer to the old ones, and the look up is done by name instead of using the pointer, the old one with the stale pointer is used. It may just happen that a new object now sits in the old address, which would explain the weird callstack.
Does this sound like a plausible explanation to you?
Thanks
The problem with the UFunctions is solved by adding them to the root set when they are created. Right after
Code: Select all
auto NoesisDelegateFunc = NewObject<UFunction>(ObjectClass, *DelegateName);
Code: Select all
NoesisDelegateFunc->AddToRoot();
I have to try to reproduce it, but I have a theory perhaps you can confirm: I think what's happening is that the same MaterialInterface is used by both the old and the new levels, but during the transition the old one is garbage collected and a new one is created at a different address. Our NoesisTypeClasses contain the pointer to the old ones, and the look up is done by name instead of using the pointer, the old one with the stale pointer is used. It may just happen that a new object now sits in the old address, which would explain the weird callstack.
Does this sound like a plausible explanation to you?
Thanks
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Hi hcpizzi,
yes, that's exactly, what we think is happening. At the end of the level, all level objects including the controller and the widgets owned by it, are cleaned up. So the materials used the next level have new addresses. The TypeClass system doesn't create new type entries for them, because types with the same names already exist. So it uses them instead, but unfortunately, the pointers are no longer valid.
yes, that's exactly, what we think is happening. At the end of the level, all level objects including the controller and the widgets owned by it, are cleaned up. So the materials used the next level have new addresses. The TypeClass system doesn't create new type entries for them, because types with the same names already exist. So it uses them instead, but unfortunately, the pointers are no longer valid.
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Thank you, that saves me the time to create a repro to test my theory.
I'll create a patch for you to try as soon as possible.
Did the other change fix the issue with the UFunctions?
I'll create a patch for you to try as soon as possible.
Did the other change fix the issue with the UFunctions?
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Hey,
regarding your suggestion about UFunctions, yes it worked.
By the way, by accident I just found the location in the code where materials are added to the root set, but unfortunately they're removed again in the destructor of the wrapper. Just had the idea that custom reference counting might help here.
Thanks.
regarding your suggestion about UFunctions, yes it worked.
By the way, by accident I just found the location in the code where materials are added to the root set, but unfortunately they're removed again in the destructor of the wrapper. Just had the idea that custom reference counting might help here.
Thanks.
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Those are the MaterialInstanceDynamic objects we create, not the Material/MaterialInstance assets, which are the ones that are being destroyed.
I've attached a patch for you to try. I may end up fixing this in a different way for 3.2.2, but at least this will allow you to move on for now.
Let me know if this does indeed fix your issue.
Thanks!
I've attached a patch for you to try. I may end up fixing this in a different way for 3.2.2, but at least this will allow you to move on for now.
Let me know if this does indeed fix your issue.
Thanks!
- Attachments
-
- MaterialInterfaceDestroyed.zip
- (689 Bytes) Downloaded 87 times
Re: Crashes due to TypeClass objects getting garbage collected after loading a new world
Sorry for the late reply. After applying your fix I could no longer reproduce the crash. Thanks
Who is online
Users browsing this forum: Ahrefs [Bot], Google [Bot] and 1 guest