Remote Config Native Collection memory leak

Windows 10, Unity 2021.1.15f1, Remote Config 2.0.1, Android Build Target

I call Remote Config Fetch on Awake once on startup and it throws the error “A Native Collection has not been disposed, resulting in a memory leak. Allocated from: Unity.Collections.NativeArray`1:.ctor(Byte[ ], Allocator)”

It appears to occur here in ConfigManagerImpl:

request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonText));

Here is the full stack trace obtained using the Jobs package with Full Stack Traces:

 [Error] A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator)
ConfigManagerImpl.DoRequest() at Library\PackageCache\com.unity.remote-config-runtime@1.0.1\Runtime\ConfigManagerImpl.cs:267
265:       request.SetRequestHeader(header.key, header.value);
266:   }
-->267:   request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonText));
268:   request.downloadHandler = new DownloadHandlerBuffer();
269:   request.SendWebRequest().completed += (AsyncOperation op) => {
ConfigManagerImpl.PostConfig() at Library\PackageCache\com.unity.remote-config-runtime@1.0.1\Runtime\ConfigManagerImpl.cs:204
202:   {
203:       var jsonText = PreparePayload(userAttributes, appAttributes);
-->204:       DoRequest(jsonText);
205:   }
ConfigManagerImpl.FetchConfigs() at Library\PackageCache\com.unity.remote-config-runtime@1.0.1\Runtime\ConfigManagerImpl.cs:188
186:   public void FetchConfigs<T, T2>(T userAttributes, T2 appAttributes) where T : struct where T2 : struct
187:   {
-->188:       PostConfig(userAttributes, appAttributes);
189:   }
ConfigManager.FetchConfigs() at Library\PackageCache\com.unity.remote-config-runtime@1.0.1\Runtime\ConfigManager.cs:96
94:   public static void FetchConfigs<T, T2>(T userAttributes, T2 appAttributes) where T : struct where T2 : struct
95:   {
-->96:       _configmanagerImpl.FetchConfigs(userAttributes, appAttributes);
97:   }
ConfigFetcher.Fetch() at Assets\Scripts\Common\Utilities\ConfigFetcher.cs:55
54:       IsFetching = true;
-->55:       ConfigManager.FetchConfigs<UserAttributes, AppAttributes>(new UserAttributes(), new AppAttributes());
56:   }
ConfigFetcher.Awake() at Assets\Scripts\Common\Utilities\ConfigFetcher.cs:34
32:       ConfigManager.SetEnvironmentID(_environmentId);
33:       ConfigManager.FetchCompleted += ApplyRemoteSettings;
-->34:       Fetch();
35:   }
36:   else if (this != Instance)
Object.Internal_CloneSingleWithParent()
Object.Instantiate()
Object.Instantiate()
Object.Instantiate()
PersistentObjectsInstantiator.Awake() at Assets\Scripts\Common\PersistantObjects\PersistentObjectsInstantiator.cs:27
25:       }
26:       DontDestroyOnLoad(gameObject);
-->27:       _presistentObjects = Instantiate(PersistentObjects, transform);
28:   }
29:   else if (this != _instance)

Any idea how to fix this? My suspicion is that UploadHandlerRaw is not wrapped inside a using statement.

1 Like

I’m facing memory leak issue too. On Mac : Unity 2021.1.14f1

Please show the (minimum) code you are using so we can try to reproduce. I’m currently using this code Code integration | Remote Config | 2.0.2-exp.1

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.RemoteConfig;
//using com.ootii.Messages;

public class RemoteConfigManager : MonoBehaviour
{
    public struct userAttributes { }
    public struct appAttributes { }

    private void Awake()
    {
        ConfigManager.FetchCompleted += ApplyRemoteSettings;

        // Set the user’s unique ID:
        //ConfigManager.SetCustomUserID("some-user-id");

        // Set the environment ID:
        //ConfigManager.SetEnvironmentID("an-env-id");

        ConfigManager.FetchConfigs<userAttributes, appAttributes>
                 (new userAttributes(), new appAttributes());
    }

    void ApplyRemoteSettings(ConfigResponse configResponse)
    {
        // Conditionally update settings, depending on the response's origin:
        switch (configResponse.requestOrigin)
        {
            case ConfigOrigin.Default:
                Debug.Log("No settings loaded this session; using default values.");
                break;
            case ConfigOrigin.Cached:
                Debug.Log("No settings loaded this session; using cached values from a previous session.");
                break;
            case ConfigOrigin.Remote:
                //MessageDispatcher.SendMessage(GAMEEVENTS.EVT_REMOTE_SETTINGS_FETCH_COMPLETE, 1);
                Debug.Log("New settings loaded this session; update values accordingly.");
                //Debug.Log("Ball Speed : "+ ConfigManager.appConfig.GetFloat("ballspeed"));
                //enemyVolume = ConfigManager.appConfig.GetInt("enemyVolume");
                //enemyHealth = ConfigManager.appConfig.GetInt("enemyHealth");
                //enemyDamage = ConfigManager.appConfig.GetFloat("enemyDamage");
                //assignmentId = ConfigManager.appConfig.assignmentID;
                break;
        }
    }

    private void OnDestroy()
    {
        ConfigManager.FetchCompleted -= ApplyRemoteSettings;
    }



    //TESTING

    private void Start()
    {
        //InvokeRepeating("Test", 10.0f, 10.5f);
    }

    void Test()
    {
        Debug.Log("Fetching again.");
        ConfigManager.FetchConfigs<userAttributes, appAttributes>
                 (new userAttributes(), new appAttributes());
    }

    //TODO If Awake doesnt fetch a value then we might have to check again after some time to fetch fresh set of values
}

This is my code. I created a new scene with just a camera and a game object called RemoteConfigSettings manager and added this script to it. If you play 2-3 times you should see the error. Im using Mac.

Got it, where does the exception occur?

I enabled full stack trace by adding entities package and using the Menu: Jobs → Leak Detection → Full Stack Traces (Expensive).

and this extra details were there in log

A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator) (at /Users/bokken/buildslave/unity/build/Runtime/Export/NativeArray/NativeArray.cs:69)
UnityEngine.Networking.UploadHandlerRaw:.ctor(Byte[]) (at /Users/bokken/buildslave/unity/build/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs:98)
Unity.RemoteConfig.ConfigManagerImpl:smile:oRequest(String) (at Library/PackageCache/com.unity.remote-config-runtime@1.0.1/Runtime/ConfigManagerImpl.cs:267)
Unity.RemoteConfig.ConfigManagerImpl:PostConfig(Object, Object) (at Library/PackageCache/com.unity.remote-config-runtime@1.0.1/Runtime/ConfigManagerImpl.cs:204)
Unity.RemoteConfig.ConfigManagerImpl:FetchConfigs(userAttributes, appAttributes) (at Library/PackageCache/com.unity.remote-config-runtime@1.0.1/Runtime/ConfigManagerImpl.cs:188)
Unity.RemoteConfig.ConfigManager:FetchConfigs(userAttributes, appAttributes) (at Library/PackageCache/com.unity.remote-config-runtime@1.0.1/Runtime/ConfigManager.cs:96)
RemoteConfigManager:Awake() (at Assets/JL_Game/Scripts/RemoteConfigManager.cs:22)

Does this help

Can you confirm it is in FetchConfigs? Simply add Debug.Log statements before and after to confirm, they will show in the logcat logs.

I added debug statements but error occurs at end while exiting the play mode

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.RemoteConfig;
using com.ootii.Messages;

public class RemoteConfigManager : MonoBehaviour
{
    public struct userAttributes { }
    public struct appAttributes { }

    private void Awake()
    {
        Debug.Log("A");
        ConfigManager.FetchCompleted += ApplyRemoteSettings;
        Debug.Log("B");
        // Set the user’s unique ID:
        //ConfigManager.SetCustomUserID("some-user-id");

        // Set the environment ID:
        //ConfigManager.SetEnvironmentID("an-env-id");
        Debug.Log("C");
        ConfigManager.FetchConfigs<userAttributes, appAttributes>
                 (new userAttributes(), new appAttributes());
        Debug.Log("D");
    }

    void ApplyRemoteSettings(ConfigResponse configResponse)
    {
        // Conditionally update settings, depending on the response's origin:
        switch (configResponse.requestOrigin)
        {
            case ConfigOrigin.Default:
                Debug.Log("No settings loaded this session; using default values.");
                break;
            case ConfigOrigin.Cached:
                Debug.Log("No settings loaded this session; using cached values from a previous session.");
                break;
            case ConfigOrigin.Remote:
                Debug.Log("GAA");
                MessageDispatcher.SendMessage(GAMEEVENTS.EVT_REMOTE_SETTINGS_FETCH_COMPLETE, 1);
                Debug.Log("GBB");
                Debug.Log("New settings loaded this session; update values accordingly.");
                //Debug.Log("Ball Speed : "+ ConfigManager.appConfig.GetFloat("ballspeed"));
                //enemyVolume = ConfigManager.appConfig.GetInt("enemyVolume");
                //enemyHealth = ConfigManager.appConfig.GetInt("enemyHealth");
                //enemyDamage = ConfigManager.appConfig.GetFloat("enemyDamage");
                //assignmentId = ConfigManager.appConfig.assignmentID;
                break;
        }
    }

    private void OnDestroy()
    {
        Debug.Log("G");
        ConfigManager.FetchCompleted -= ApplyRemoteSettings;
        Debug.Log("H");
    }



    //TESTING

    private void Start()
    {
        //InvokeRepeating("Test", 2.0f, 2.5f);
    }

    void Test()
    {
        Debug.Log("Fetching again.");
        Debug.Log("E");
        ConfigManager.FetchConfigs<userAttributes, appAttributes>
                 (new userAttributes(), new appAttributes());

        Debug.Log("F");
    }

    //TODO If Awake doesnt fetch a value then we might have to check again after some time to fetch fresh set of values
}

In Play mode? So this only happens when running in the Editor, and not on a device? The original post mentioned Android as the target platform. What is “GetStacktrace(int)”

If I enable Full as shown below then “GetStacktrace(int)” appears in log messages trace
I have not tested it on device yet but my build target is set to iOS

7341857--892865--Screenshot 2021-07-19 at 10.14.57 PM.png

I have only tested it on the editor, latest Unity version on Windows 10. This is the code that initiates the whole process:

using Sirenix.OdinInspector;
using Unity.RemoteConfig;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;

namespace Common.Utilities
{
    class ConfigFetcher : MonoBehaviour
    {
        public static ConfigFetcher Instance { get; private set; }

        public bool IsFetching { get; private set; }
        public int FetchCount { get; private set; }
        public float LastFetchTime { get; private set; }

        [Required] [SerializeField] private string _environmentId;

        public struct UserAttributes
        {
        }

        public struct AppAttributes
        {
        }

        private void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                ConfigManager.SetEnvironmentID(_environmentId);
                ConfigManager.FetchCompleted += ApplyRemoteSettings;
                Fetch();
            }
            else if (this != Instance)
            {
                Destroy(gameObject);
            }
        }

        private void OnDestroy()
        {
            ConfigManager.FetchCompleted -= ApplyRemoteSettings;
        }

        public void Fetch()
        {
            if (IsFetching)
            {
                return;
            }

            IsFetching = true;
            ConfigManager.FetchConfigs<UserAttributes, AppAttributes>(new UserAttributes(), new AppAttributes());
        }

        void ApplyRemoteSettings(ConfigResponse configResponse)
        {
            FetchCount++;
            LastFetchTime = UnityEngine.Time.realtimeSinceStartup;
            IsFetching = false;
        }
    }
}

The error also appears elsewhere, when I opened the Remote Config windows and pushed an update while the players wasnt running:

[Error] A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator)
UnityWebRequest.Put()
Unity.RemoteConfig.Editor.<_PutConfig>d__64.MoveNext() at Library\PackageCache\com.unity.remote-config@2.0.1\Editor\RemoteConfigWebApiClient.cs:385
383:   string url = string.Format(RemoteConfigEnvConf.putConfigPath, cloudProjectId, configId);
-->385:   var request = Authorize(UnityWebRequest.Put(url, payload));
386:   yield return request.SendWebRequest();
RemoteConfigWebApiClient.UpdateCoroutine() at Library\PackageCache\com.unity.remote-config@2.0.1\Editor\RemoteConfigWebApiClient.cs:819
817:   if (m_webRequestEnumerator.Current == null)
818:   {
-->819:       m_webRequestEnumerator.MoveNext();
820:   }
821:   else if (m_webRequestEnumerator.Current.isDone)
RemoteConfigWebApiClient.Update() at Library\PackageCache\com.unity.remote-config@2.0.1\Editor\RemoteConfigWebApiClient.cs:807
805:   private static void Update()
806:   {
-->807:       UpdateCoroutine();
808:   }
EditorApplication.Internal_CallUpdateFunctions()

I believe it has to do with UploadHandlerRaw not being wrapped inside a using statement. Any comment on that idea?

It’s possible, we will take a look

Any updates? I’m still getting exceptions every time I run my app.
I actually know the solution, add IDisposable interface to RCUnityWebRequest and in ConfigManagerImpl.cs function DoRequest() wrap var request = new RCUnityWebRequest(); inside a using statement. I did it myself but everytime I run my game it resets the code since it is inside a unity package. Can you please update the package ASAP or let me know how to prevent my edits from being overwritten by unity?

I am also observing this all the time… it’s very annoying. Can you fix this please?

Can you confirm it’s only showing in the Editor, not on devices, and not a crashing error?

Hi Jeff! I confirm - no crash, it happens in the editor only.

Hi Jeff, is there already an issue created on issue tracker for this problem? When do you think you can get it fixed?

Hi @ramsayamarin

We’re taking a look at this bug. In regards to your question to having a version of the package that will not be overwritten when you make a change to the code; I believe you can change the reference to the current installed version of the Remote Config package by referencing the local filesystem path and adding it locally from the Package Manager UI: https://docs.unity3d.com/Manual/upm-ui-local.html

Guys are you planning to post some update here in this thread? Or it’s just going to get fixed in some upcoming release?

1 Like

Hi @wilczarz_84 don’t have anything to report currently. We will update on this forum thread when we have a patch you can apply, and expected release for a package containing the fix