Origin
Reported by a user on the GDevelop Big Game Jam 9 forum:
https://itch.io/jam/gdevelop-big-game-jam-9/topic/6382098/error-in-gdevelop-physics3d
The user got the following crash when switching levels by pausing the current scene and starting a new one (push scene), with Physics3D objects in the scenes:
Aborted(OOM). Build with -sASSERTIONS for more info.
RuntimeError: Aborted(OOM). Build with -sASSERTIONS for more info.
at ... jolt-physics.wasm ...
at new JoltInterface ...
at new Physics3DSharedData ...
They worked around it by using "Change scene" (replace) instead of "Pause and start a new scene".
Root cause
In Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.ts, the Jolt WASM memory held by the shared data is only freed in the scene unloaded callback:
gdjs.registerRuntimeSceneUnloadedCallback(function (runtimeScene) {
const physics3DSharedData = runtimeScene.physics3DSharedData;
if (physics3DSharedData) {
Jolt.destroy(physics3DSharedData.contactListener);
Jolt.destroy(physics3DSharedData._tempVec3);
Jolt.destroy(physics3DSharedData._tempRVec3);
Jolt.destroy(physics3DSharedData._tempQuat);
Jolt.destroy(physics3DSharedData.jolt);
runtimeScene.physics3DSharedData = null;
}
});
There is no registerRuntimeScenePausedCallback for Physics3D. When a scene is paused (push), its JoltInterface (a full physics world, plus all bodies/shapes/listeners) keeps living in the WASM heap. Pushing a second scene with Physics3D allocates a brand new JoltInterface, so each level swap leaks the previous physics world. After 2–3 levels the WASM linear memory is exhausted → Aborted(OOM).
This does not happen with "Change scene" (replace) because that triggers the unloaded callback and the world is freed.
The same root cause likely affects the 2D Physics behavior (Box2D); worth checking it too.
Possible fixes
- Free the Jolt world on scene pause and rebuild it on resume. Add
registerRuntimeScenePausedCallback mirroring the unloaded cleanup, and on Resumed recreate the shared data + recreate bodies from each behavior. The trade-off is the loss of in-flight physics state (velocities, active contacts, constraints) across a pause — arguably acceptable since the scene was paused.
- Share a single
JoltInterface across scenes at the RuntimeGame level instead of per-scene. Bodies stay per-scene but the physics world is reused. Needs care if more than one Physics3D scene can ever run simultaneously.
- As a minimum, document the limitation and warn in the editor when a project uses "Pause and start a new scene" together with Physics3D.
Option 1 seems the safest and most contained.
Origin
Reported by a user on the GDevelop Big Game Jam 9 forum:
https://itch.io/jam/gdevelop-big-game-jam-9/topic/6382098/error-in-gdevelop-physics3d
The user got the following crash when switching levels by pausing the current scene and starting a new one (push scene), with Physics3D objects in the scenes:
They worked around it by using "Change scene" (replace) instead of "Pause and start a new scene".
Root cause
In
Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.ts, the Jolt WASM memory held by the shared data is only freed in the scene unloaded callback:There is no
registerRuntimeScenePausedCallbackfor Physics3D. When a scene is paused (push), itsJoltInterface(a full physics world, plus all bodies/shapes/listeners) keeps living in the WASM heap. Pushing a second scene with Physics3D allocates a brand newJoltInterface, so each level swap leaks the previous physics world. After 2–3 levels the WASM linear memory is exhausted →Aborted(OOM).This does not happen with "Change scene" (replace) because that triggers the unloaded callback and the world is freed.
The same root cause likely affects the 2D Physics behavior (Box2D); worth checking it too.
Possible fixes
registerRuntimeScenePausedCallbackmirroring the unloaded cleanup, and onResumedrecreate the shared data + recreate bodies from each behavior. The trade-off is the loss of in-flight physics state (velocities, active contacts, constraints) across a pause — arguably acceptable since the scene was paused.JoltInterfaceacross scenes at theRuntimeGamelevel instead of per-scene. Bodies stay per-scene but the physics world is reused. Needs care if more than one Physics3D scene can ever run simultaneously.Option 1 seems the safest and most contained.