PIE is a simulation of what a build would look like. If the GameInstance was created at editor load and persisted through runs it would not be an accurate representation of build state at all – since in a build, when the game instance is created, it truly persists for the session as a singleton.
Also, there’s nothing that says singletons are necessarily run-once – they just need to be self-constructing with a static reference to the a single instance, usually with a guarantee or run-once strategy. In UE4 they need that run-once guarantee, hence why GameInstance exists at all. Many of the if guards that protect singletons from duplicate instantiation are completely ignored, since as developers we usually have no reason to suspect duplicates and don’t want to waste CPU in bool checks on the hot loop. What’s important about a singleton is that there’s always one instance-- since we change levels a lot, it’s not unheard of to have singleton patterns on objects that only persist for the duration of level. In my Unity game, for example, I have 4 or 5 player interaction singletons that get instantiated and destroyed every time a Local Network Player Controller is created. There are video breakdowns on popular games like Overwatch where this practice is considered commonplace.
In game engines like Unity and Unreal it is difficult to have true singletons with all the strict rules so you almost always use the singleton pattern loosely. For example, because you would be outside the scope of the engine and unable to interact with the APIs. In Unity, we use pseudo-singletons instantiated in Awake() because we’re not even allowed to use constructors in MonoBehaviours. In Unreal, we do something very un-singleton like and instantiate our singletons from the GameInstance.
Lastly – there’s nothing wrong with destroying and reconstructing your singletons! It can be useful for clearing state between sessions of things, or when a user logs out, stuff like that