Simple-WebXR-Unity
Simple-WebXR-Unity copied to clipboard
Shared array breaks after performing memory intensive operations
Hello, when trying to implement the library, I've come across an issue.
My application relies heavily on downloading assets at runtime. I noticed, that when downloading and parsing files, the Enter VR button would sometimes stop working, or the VR view would freeze if a session was already running. By adding console.log() in various parts of the .jslib, I found that _dataArray would become unassigned/set to all zeroes after downloading a file.
I think it may be related to garbage collection, or some other memory optimization. I tried using malloc in the .jslib script, and GCHandle in pinned mode in the .cs to ensure that memory does not get moved arround, however, I was unable to work around this issue. I tested the issue in Unity versions 2020.3.48, 2021.3.31 and 2022.3.37.
I've come up with a minimal reproduction sample:
Scene:
- single camera with the Script.cs script attached.
Script.cs
using System.Collections.Generic;
using UnityEngine.Networking;
using Newtonsoft.Json.Linq;
using Rufus31415.WebXR;
using System.Collections;
using System.Linq;
using UnityEngine;
public class Script : MonoBehaviour
{
public string Url = "https://www.tracenacademy.com/api/MobData";
public List<string> Characters;
private IEnumerator Start()
{
SimpleWebXR.EnsureInstance();
SimpleWebXR.SessionStart.AddListener(EnableVRMode);
using (UnityWebRequest www = UnityWebRequest.Get(Url))
{
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
var str = www.downloadHandler.text;
if (!string.IsNullOrEmpty(str))
{
var array = JArray.Parse(str);
Characters = array.Select(line=>line.ToString()).ToList();
Debug.Log(Characters.Count);
}
}
}
Debug.Log("Ready");
}
private void EnableVRMode()
{
Debug.Log("VR Enabled");
}
}
If SimpleWebXR.EnsureInstance(); is moved behind the using statement, the issue does not occur, however in my case, files can be downloaded at any time, which causes the shared array to desync.
Url comes from a public repository https://github.com/SimpleSandman/UmaMusumeAPI
There are no errors in the console or anything the like when the problem occurs. I'd be grateful if someone with more knowledge about the implementation could look into this.
Hi, thank you for your detailed report and for providing a reproduction sample. From your description, it seems the problem occurs due to shared memory (_dataArray in the .jslib) being modified or deallocated unexpectedly. The symptoms, such as VR session freezing or the Enter VR button becoming unresponsive, suggest a potential conflict between UnityWebRequest, the underlying WebGL memory model, and how SimpleWebXR manages its shared arrays.
Potential Causes
-
Garbage Collection (GC): As you mentioned, the shared memory could be moved or collected by Unity's GC or the browser’s WebAssembly memory model. If
_dataArrayis not properly pinned or its lifecycle isn't tightly controlled, operations like downloading assets or parsing JSON may inadvertently trigger issues. -
Thread Blocking: While UnityWebRequest operates asynchronously, it might still interfere with the WebGL main thread in specific cases, especially if Unity or the browser tries to allocate/deallocate memory during runtime.
-
Order of Initialization: Moving
SimpleWebXR.EnsureInstance();after theUnityWebRequestresolves the issue, which suggests that the timing of initialization and resource allocation is critical.
Suggestions and Workarounds
While we investigate further, here are some possible ways to mitigate the issue:
-
Ensure Proper Memory Handling:
- Ensure
_dataArrayin the .jslib is initialized and used consistently. If possible, manually pin it or ensure it's re-initialized before critical VR operations. - Avoid accessing or modifying
_dataArrayduring file downloads unless necessary.
- Ensure
-
Avoid Simultaneous Memory Operations:
- Consider isolating the asset download process from VR session management to reduce the risk of interference. For example, you could queue asset downloads and pause VR session interactions until they are complete.
-
Test on Different Browsers:
- As WebGL behavior can vary between browsers, testing on Chrome, might help identify whether it’s a Unity or browser-specific issue.
Thank you for the reply. From suggested workarounds, I though 2. had a chance to work, but unfortunately, it does not. Ending the session does not clear the initialization flag, so when it is re-enabled, an attempt is made to use the old data array, which has since been re-allocated (I presume). Calling the initialization manually leads to a different error, which I'm still investigating. Overall, there are many static variables that make it difficult to try to re-initialize the VR service. I will update you if I find a different workaround, but it doesn't look promising.
I found that a similar problem was addressed in your other repository unity-webxr-export #65. I wasn't able to adapt that solution to this one though, as during the initialization process, many different variables are set in the array, therefore, it's not enough to just re-initialize the arrays when the values get reset. Of course I could just be doing something wrong. I tried:
-
changing all references of _dataArray, _byteArray and _handsArray to Module.*array*, checking the array length at the start of each function and re-initializing them as needed
-
same as above, but calling
InitWebXRwhenever one of the lengths is incorrect
This resulted in the game showing only white screen, I'm not sure what exactly happened, but it did not work as I'd expect. I also tried pinning the Unity arrays using GCHandle.Alloc();