Rufus31415 / Simple-WebXR-Unity

⭐ Bringing WebXR to Unity 3D ! B-)
https://rufus31415.github.io/webxr/MRTK-HandInteraction/
MIT License
576 stars 82 forks source link

Shared array breaks after performing memory intensive operations #60

Open katboi01 opened 5 days ago

katboi01 commented 5 days ago

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:

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.

Rufus31415 commented 1 day ago

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

  1. 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 _dataArray is not properly pinned or its lifecycle isn't tightly controlled, operations like downloading assets or parsing JSON may inadvertently trigger issues.

  2. 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.

  3. Order of Initialization: Moving SimpleWebXR.EnsureInstance(); after the UnityWebRequest resolves 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:

  1. Ensure Proper Memory Handling:

    • Ensure _dataArray in 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 _dataArray during file downloads unless necessary.
  2. 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.
  3. 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.