This question was created in reference to: [Cannot allocate more root [Content removed]
Dear all,
I’m back for this very same subject which concerns the following message:
Error: Cannot allocate more root pages 32768/32768. Pool resource has grown to maximum size of 2048MB. [2025.06.21-17.08.55:788][ 8]LogWindows: Error: 1024MB is spent on streaming data, leaving 1024MB for 32768 root pages.
Basically, I was able to avoid it by reducing the number of unique static meshes, and for the one that were converted from a dynamic mesh, I was applying a merge of the dynamic meshes inside an actor before to solve this.
Since, we moved to Unreal 5.6 and a lot more actors were added, some of them splitted because of their huge size, and we had again this message. I am in the editor.
What troubles me is that I never load the whole level at once, only by small area, still, if I see that the new instances are added to the pool with the function FStreamingManager::Add, FStreamingManager::Remove is never called when I unload the data.
It seems that, in the function FResources::ReleaseResources, I do not reach GStreamingManager.Remove because “if (PageStreamingStates.Num() == 0) return false“ rejects me all the time.
Having PageStreamingStates indicates there is Nanite rendering data to be released, so if it’s empty then it doesn’t think there’s anything to do. If you set a breakpoint in FResources:AddResources() for your new Nanite meshes you should be able to see if they ever start with PageStreamingStatesor not.
How are converting your dynamic meshes into static ones? Did you make a custom cell transformer it like the FastGeo plugin that finds all the actors with identical meshes and turns them into instanced static meshes or are you merging meshes like FDynamicMeshEditor::AppendMesh, converting to a StaticMesh and then converting it to Nanite?
Thank you for helping me! So I checked just after the conversion what was the state of PageStreamingStates in the function FResources::InitResources (and not AddResources which does not exist) and it is set. Of course, the resource is added to the pool. Please see the following screenshots:
[Image Removed]Of course, after this, unloading everything and I quit early in all the ReleaseResources that are called so FStreamingManager::Remove is totally ignored.
By the way, it is not only after a conversion, it happens too with a basic load / unload area. The pool can only grow. Even if I bypass this part (batch of conversions) by setting a very low value for r.Nanite.Streaming.StreamingPoolSize, I’m telling myself that I will still meet the problem in Runtime.
For your last questions. No, I’m not using a custom cell transformer but the function UGeometryScriptLibrary_StaticMeshFunctions::CopyMeshToStaticMesh and I apply the Nanite properties afterwards.
I think I finally got it! My whole problem is that the static meshes were never unloaded in the editor, even if I called explicitly a garbage collector after unloading the actors. It seems that they are flagged as GARBAGE_COLLECTION_KEEPFLAGS so ignored during that process.
So I tried to force a state allowing this cleaning through this code. I finally entered in the function GStreamingManager.Remove.
for (TObjectIterator<UObject> vIt; vIt; ++vIt)
{
if (!vIt->HasAnyFlags(RF_Standalone)) continue;
UPackage* vPackage = vIt->GetOutermost();
if (!vPackage->GetName().StartsWith(TEXT("/Game/CompiledLevels")) &&
!vPackage->GetName().StartsWith(TEXT("/Game/ProjectData"))) continue;
if (!vIt->IsA(UStaticMesh::StaticClass()) &&
!vIt->IsA(UMaterialInterface::StaticClass()) &&
!vIt->IsA(UTexture::StaticClass())) continue;
vIt->ClearFlags(RF_Standalone);
UE_LOG(LogTemp, Warning, TEXT("Standalone mesh => %s"), *vIt->GetFullName());
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
I don’t know if it is the best way to do but it seems to work on a light level. I would appreciate your feedback on it especially if this approach is dangerous or not. In any case, I will test it on my huge level.
As an update, my function above works if we do simple load / unload of area but in my case where I do a conversion before, it seems that my meshes are bounded to :
It turns out there was a straightforward solution for this, UPackageTools::UnloadPackages, which handles all aspects to consider (including the one related to transactions). I’m testing it but I’m confident and keep you informed.
You can close this case, forcing the converted static mesh to unload with UPackageTools::UnloadPackages was the solution. It solved my memory issues and above all, the Nanite resources allocation which was the topic of this thread.
I didn’t know that unloading the level actors was not sufficient to trigger the unloading of the assets. I’ll be more cautious about that in the future.