Instantiate and destroy MarsSession at runtime

Hi,

I’m trying to load MarsSession dynamically by instantiating a prefab that holds it + all other references.
So far I’ve succeeded but I have 2 issues:

  1. I can’t change the world scale parameter from the prefab scene - im getting error that tells me that current scene does not contain mars session (see image)

  2. I have memory leaks when i’m unloading the mars session (by simply destroying it), I don’t see the memory get clean and it always rising when i’m instantiating the mars session again. I’m also get memory leaks when im unloading the scene and not just destroying the prefab. I’m of course making to clean all the references and resources.

What i’m doing wrong? is MarsSession designed to be part of a scene and not part of a prefab? I shouldn’t instantiate it? I didn’t see anything about it in the documents.

Thanks, Udi.

About the memory leaks, here’s example of memory that not get cleaned…

MARSSession currently is currently designed to be used directly in a scene, I currently don’t recommend trying to create and destroy it at runtime. You should be able to have it exist in a prefab, but that prefab must already exist in a scene.

You have 2 options for dealing with dynamism:

  1. Have a MARSSession in each of your scenes - this is the simplest option if you have discrete scenes with no overlap. The mars database will be destroyed and recreated on each transition, so you won’t be able to persist proxy matches between scenes. Use if your scenes are self contained or you only have one main scene where you stage content in and out. Our sample / test content does this.

  2. Have one MARSSession in the default scene, and additively load/unload other scenes with Proxies, etc. You can still create/destroy prefab instances with proxies in them at runtime just fine. This has been the recommendation we’ve given to most people trying to do dynamic content with MARS, including other teams at Unity.

MARSSession is designed as a very specific singleton that hooks into a lot of background systems, so it’s possible that being loaded/unloaded as a prefab is messing with the lifecycle in ways it was never intended.

I’ll still see if MARSSession prefab create/destroy is something we can fix in the future.

Thanks for the response, I’ll try the solutions you mention.

It’ll be really nice to see a fix like this in the future.

hello @Udi-Beres , to add up to @thomas_key 's response. The MARS Session would not work in that case since if you noticed you are in prefab isolation mode; if you go back to a normal scene the scale should appear

Yeah I’ve noticed it. The MARS Session still work if you are instantiating it with a prefab, the issue is the scaling and much worst - memory leaks (when destroyed).

@thomas_key I’ve tried to start the app with MARSSession located in some default scene that always live, and than instantiate a proxy in additive scene, I’m using the face mask so I need the front camera.

I’ve 2 issues right now:

  1. The front camera does not get activated when I’m loading the Proxy with the face mask. I didn’t found any api on MARSSession that let me do that.

  2. The back camera is always working since the MARSSession is alive an it need a Main camera as a child. There is something I can do to stop the physical camera when I don’t need it?

Hi @Udi-Beres , to answer your questions about the camera:

  1. You can switch the camera by using the API IUsesCameraTexture.RequestCameraFacingDirection. If you add a MonoBehaviour to your scene that implements IUsesCameraTexture, you can call this.RequestCameraFacingDirection(CameraFacingDirection.User)
    in the behavior. This only works if you are using AR Foundation 4 or later.

  2. You can stop the camera by pausing the AR session with IUsesSessionControl.PauseSession, which uses the same interface extension method pattern as above. There’s a sample script in this post .

Hi @amydigiov_Unity thanks for the response.

implementing the interfaces you mentioned helped. but now I have new issue (hopefully the last):

The face tracking is not working :confused:
When im loading the scene with the Proxy I see the front camera but non of the filters that I create get attached to my face. I don’t see errors on the logcat (or any special warnings).
Its seem that the Proxy is not communicate with MARSSession

Also I have this script (attached to Proxy) that give me info about the ar state, currently its not working, if i’m loading the scene with Proxy and MARSSession together everything works fine.

public class AREventHandler : MonoBehaviour, IMatchAcquireHandler, IMatchUpdateHandler, IMatchLossHandler
{
    public void OnMatchAcquire(QueryResult queryResult) => Debug.Log($"OnMatchAcquire!");

    public void OnMatchUpdate(QueryResult queryResult) =>  Debug.Log($"OnMatchUpdate");

    public void OnMatchLoss(QueryResult queryResult) => Debug.Log($"OnMatchLoss!");
}

@Udi-Beres - I’m investigating the memory leak right now. What kind of profiler information / errors are you getting? I want to verify I’m seeing the same results if I create/destroy a MARSSession from a prefabs.

I also wanted to confirm you’re testing in a device build vs just testing in the editor.
If testing in playmode in the editor, the overhead of profiling can distort your test results.

@thomas_key Yes, I’m only testing on a device and not the editor. I’ve added a zip file that contains snapshots from the profiler and the memory profiler. The first snapshot of each profiler is the snapshot of the first session and the second snapshot of each profiler is a snapshot after a couple of sessions where I’ve instantiated and destroyed the prefab a couple of times.

To make things clear - I’m instantiating a prefab that contains a Session + Proxy that uses a face mask.

Also I’ve added an image from the memory profiler of the memory that did not get released after destroying the prefab - it’s an HashSet that did not get cleared.

Zip file

I can take a deeper look if you’re willing to file a bug report (with project attachment) through the bug reporter and post the bug# here. I’ll take a look at this capture tomorrow.

In the meantime, I can recommend de-activating and re-activating the MARSSession GO and any relevant Proxy GOs as you need to. This works well with what’s already available and doesn’t require a scene change.

Thanks, I’ll fill out a bug report.

About your second solution, The issue is that I have a multi purpose scene with strict architecture about how to load components, I can’t just put the MARSSession go there and activate/disable it since it’ll break the pattern me and other developers created.

I’m willing to go on the first solution that you suggested - keep the MARSSession live in another scene and instantiate and destroy only the Proxy. I’m close to solving this but I have only 1 issue left: the face recognition not working when I’m trying to make things work this way.

The bug report

1 Like

Taking a look at this now.

As a heads up @Udi-Beres , you should edit your post to only include the ticket # from Fogbugz. If you post the link, anyone can see other bugs you posted, which can be an issue if you’re working on confidential client projects or NDA’d platforms in the future. You don’t seem to have any, but I always suggest this to folks when they post FogBugz links.

Hi there, @Udi-Beres !

Thank you for reporting this issue. I was able to take a look at the project you shared with your bug report, and identify the issue. If you click on the 1 in the References column for the HashSet.Slot objects you were seeing, you can follow the trail up to our Pools class in the MARS database code.

The MARS databases uses collection pools to avoid thrashing the heap when we add/remove data. By design, we hold on to this memory between scene loads, which includes destroying the MARS session. As it turns out, there is no way to null out these collection pools and completely reclaim the memory, which was a bit of an oversight. In our testing, these retained collections, since their contents were cleared on shutdown, never ended up taking up a significant amount of memory. Seeing 5.3MB of retained hash set slots is definitely a surprise, and I can understand why this is a concern for you. I wasn’t able to replicate the exact scenario in your memory snapshots, but the issue remains that these collections will grow to some maximum size and never get freed.

We’re in the middle of wrapping up our next release, and unfortunately a fix for this would introduce too much risk for MARS 1.4.0. However, we will work on mitigating this issue in the next patch. In the meantime, you should be able to embed the MARS package (copy it from the package cache to the project Packages folder) so that you can make changes and fix this just in your project.

The file you’ll want to look at is Packages/com.unity.mars/Runtime/Scripts/Backend/Pools.cs. You’ll see that we initialize these pools in a static constructor and never release them. What I would recommend is that you add a static method to null out and/or re-initialize these pools when you load/unload MARS. Of course, this is somewhat risky, as you will need to make sure you re-initialize the pools by the time that you need MARS again. If all goes well, we’ll have a 1.4.1 version that reigns in this greedy memory pooling. I’ll let you know when this is ready.

1 Like

Hi, @mtschoen , thank you very much. I’ll sure try what you suggest till you’ll release a fix.