A Native Collection has not been disposed, resulting in a memory leak.

Hi,

I’m getting this log error in the editor since updating to Unity 2021.1.13f, previously I was on version 2020.3.7f

Log:
A Native Collection has not been disposed, resulting in a memory leak. Enable Full StackTraces to get more details.

Searching the forums and google I can only find information on this issue relating to dots and entities but I am not using dots or entities. I tried turning on stack trace logging in player settings but it doesn’t reveal anything useful.

1 Like

Probably has something to do with an internal Unity package that you have installed. Unity is using Burst more and more under the hood. How many custom packages do you have installed?

Yeah possibly. I don’t have any packages too out of the ordinary though. And nothing new since updating to this version of Unity.

ProGrids may use it, especially since it is experimental, or the other packages installed.

You may just need to download the Burst package and Jobs package (get both so you can turn on memory tracking) enabled it and see what is causing the issue. My bet is one of your custom packages.

I’ll give it a go.

It looks like it’s ChilliConnect (SdkCore). Or unity networking (UnityEngine.Networking.UploadHandlerRaw)

A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
Unity.Collections.NativeArray1:.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) SdkCore.HttpSystem:CreateUnityWebRequest(String, IDictionary2, Byte[ ]) (at Assets/ThirdPartyPackages/ChilliConnect/CoreSource/Http/HttpSystem.cs:216)
SdkCore.d__7:MoveNext() (at Assets/ThirdPartyPackages/ChilliConnect/CoreSource/Http/HttpSystem.cs:168)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) (at /Users/bokken/buildslave/unity/build/Runtime/Export/Scripting/Coroutines.cs:17)

1 Like

And fixed it:

Thanks for the help @8bitgoose

Here’s the solution for any other ChilliConnect users out there:

Inside the HttpSystem.cs file:
Make sure the UnityWebRequest disposes of its handlers when it’s disposed.

private UnityWebRequest CreateUnityWebRequest(String url, IDictionary<string, string> headers, byte[] body)
        {
            var webRequest = new UnityWebRequest(url);
            webRequest.method = UnityWebRequest.kHttpVerbPOST;

            // Set the headers
            foreach(var pair in headers)
            {
                webRequest.SetRequestHeader(pair.Key, pair.Value);
            }

            // Handlers
            webRequest.uploadHandler = new UploadHandlerRaw(body);
            webRequest.downloadHandler = new DownloadHandlerBuffer();

// make sure this gets cleaned up.
// ADD IN THESE TWO LINES
            webRequest.disposeUploadHandlerOnDispose = true;
            webRequest.disposeDownloadHandlerOnDispose = true;

            return webRequest;
        }

And add webRequest.Dispose(); where required.

private IEnumerator ProcessRequest(String url, IDictionary<string, string> headers, byte[] body, Action<HttpResponse> callback)
        {
            ReleaseAssert.IsTrue(callback != null, "The callback must not be null when sending a request.");

            int responseCode = 500;
            float delayInSeconds = 0.0f;
            float delayIncrementInSeconds = 1.0f;
            float delayMultiplier = 2.0f;
            int retryAttempt = 1;

            for(int retries = 4; retries != 0; --retries)
            {
                if(retries < 4){
                    headers.Remove("X-Chilli-Retry");
                    headers.Add("X-Chilli-Retry", retryAttempt.ToString());
                    retryAttempt++;
                }

                yield return new WaitForSecondsRealtime(delayInSeconds);

                UnityWebRequest webRequest = CreateUnityWebRequest(url, headers, body);
                ReleaseAssert.IsTrue(webRequest != null, "The webRequest must not be null when sending a request.");

                m_logging.LogVerboseMessage(string.Format("Sending request after delay {1}. Retries remaining {0}.", retries, delayInSeconds));

                yield return webRequest.SendWebRequest();

                responseCode = (int)webRequest.responseCode;

                if(ERROR_CODES.Contains(responseCode) == false || retries == 1)
                {
                    m_logging.LogVerboseMessage(string.Format("Request sent with response code {0}", responseCode));
                    ProcessSentRequest(webRequest, responseCode, callback);

                    // DISPOSE OF THIS!
                    webRequest.Dispose();
                    break;
                }

                if(delayInSeconds == 0.0f){
                    delayInSeconds += delayIncrementInSeconds;
                } else {
                    delayInSeconds += delayMultiplier;
                }

                // DISPOSE OF THIS!
                webRequest.Dispose();
            }
        }

Cheers.

3 Likes

Glad I could be of help. Because of C#, many of us are not used to actually having to dispose of stuff!

Running into the same issue here, Unity 2021.2.18f1. I’ve tried adding the disposeUpload/disposeDownload handler bools before my SendWebRequest and everything is wrapped in a Using block so I just can’t figure out why its still leaking. Any thoughts? I’ve got all 3 disposes peppered throughout and it still leaks.

public IEnumerator RemoveServerInternal()
    {
        WWWForm serverData = new WWWForm();
        print("Network List Communication Manager: Removing Server Entry");

        // Assign all the fields required.
        serverData.AddField("serverKey", AuthKey);
        serverData.AddField("serverUuid", InstanceServerId);

        using (UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequest.Post(Server + "/remove", serverData))
        {
            www.disposeUploadHandlerOnDispose = true;
            www.disposeDownloadHandlerOnDispose = true;

            yield return www.SendWebRequest();

            if (www.responseCode == 200)
            {
                print("Successfully deregistered server with the NetworkListServer instance!");
                www.Dispose();
                www.uploadHandler.Dispose();
                www.downloadHandler.Dispose();
            }
            else
            {
                Debug.LogError($"Failed to deregister the server with the NetworkListServer instance: {www.error}");
                www.Dispose();
                www.uploadHandler.Dispose();
                www.downloadHandler.Dispose();
            }
         
            www.Dispose();
            www.uploadHandler.Dispose();
            www.downloadHandler.Dispose();
        }

        yield break;
    }

If your frame rate is too high you’ll get these even if it isn’t about your code. Internal Unity allocations leaking.

2 Likes

Interesting, did not know that. Right now I’m seeing the leak when I stop the editor and I call the remove function above, I wonder if things are closing before the dipose is happening.

There are some very weird things that can happen with dispose. Like if you set a struct to another struct, dispose the first struct and then try and dispose the second struct. You will get an error since the first struct had its is created set to false but the copied struct did not. You really have to be aware of passing structs around.

1 Like

2021.3.2f1

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:95)
UnityEngine.Networking.UnityWebRequest:SetupPost(UnityWebRequest, String) (at /Users/bokken/buildslave/unity/build/Modules/UnityWebRequest/Public/WebRequestExtensions.cs:176)
UnityEngine.Networking.UnityWebRequest:Post(String, String) (at /Users/bokken/buildslave/unity/build/Modules/UnityWebRequest/Public/WebRequestExtensions.cs:157)

Same problem with
UnityWebRequest

1 Like

Same problem here, tried many suggestions like use Dispose on UnityWebRequest object and it’s handlers, wrap into using statement, clear every object using in procedure, but the error keeps appearing

Unity version: 2021.2.9f1 personal.

line 346 in BaseServerConnect: using (UnityWebRequest request = UnityWebRequest.Post(uri, “POST”))

(it is in the end of another procedure outside using)
line 318: callOnComplete?.Invoke(result);

A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
Unity.Collections.NativeArray1:.ctor(Byte[ ], Allocator) UnityEngine.Networking.UploadHandlerRaw:.ctor(Byte[ ]) UnityEngine.Networking.UnityWebRequest:SetupPost(UnityWebRequest, String) UnityEngine.Networking.UnityWebRequest:Post(Uri, String) <PostDataToServer>d__181:MoveNext() (at Assets\Scripts\BaseServerConnect.cs:346)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
UnityEngine.MonoBehaviour:StartCoroutineManaged2(MonoBehaviour, IEnumerator)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
Battle:LaunchGetStageInfo(Int32, MonoBehaviour) (at Assets\Scripts\FromAE\Battle\Battle.cs:374)
BattleScript:StartStageControl() (at Assets\Scenes\Battle\BattleScript.cs:217)
BattleScript:StartAfterBattleLoaded() (at Assets\Scenes\Battle\BattleScript.cs:61)
BattleScript:BattleListLoadedHandler(Object, List`1) (at Assets\Scenes\Battle\BattleScript.cs:111)
Battle:OngoingBattlesLoadedHandler(String) (at Assets\Scripts\FromAE\Battle\Battle.cs:197)
d__17:MoveNext() (at Assets\Scripts\BaseServerConnect.cs:318)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

Same problem here. It’s super frustrating. I am using a using statement and Disposing the request and using:
request.disposeUploadHandlerOnDispose = true;
request.disposeDownloadHandlerOnDispose = true;

as well. We should probably report a bug for this?

same. only getting after upgrading to Unity 2021.1.13f

I have the same issue in Unity 2021.3.5. I keep getting this error a few seconds after sending a POST or PUT request. Disposing the UnityWebRequest does not work.

I tried:

webRequest.disposeUploadHandlerOnDispose = true;
webRequest.Dispose();
webRequest.uploadHandler.Dispose();

I’m running out of options here. Does anyone have a fix for this?

Are you using the

UnityWebRequest.Post(uri, postData);

command?
If yes, then keep in mind, that they also create an UploadHandler within the “Post” command, so you Must not create your own UploadHandler!
I would recommend, using the “new UnityWebRequest(uri,data)” constructor instead like in the posts above.
I created the following abstract class here for all Post / Get requests. All you have to do is derive from it and you can use its Get / Post commands in all your API:

namespace Mavon.ServerCommunication
{
    public abstract class BackendBaseUnityWebRequest
    {
#if UNITY_EDITOR
        public const string BackendURL = "http://127.0.0.1:2000"; // REPLACE THIS WITH YOUR LOCAL SERVER URL
#else
    public const string BackendURL = "https://MyAPI.com; // REPLACE THIS WITH YOUR SERVER URL
#endif
        public IEnumerator GetRequest<T> ( string requestURL, Action<string> error, Action<T> success)
        {
            using UnityWebRequest webRequest = UnityWebRequest.Get(BackendURL + requestURL);
            webRequest.SetRequestHeader("withCredentials", "true");
            yield return webRequest.SendWebRequest();

            HandleRequestResult(webRequest, error, success);
        }
        public IEnumerator PostRequest<T>(string postData, string requestURL, Action<string> error, Action<T> success)
        {
            using UnityWebRequest webRequest = new (BackendURL + requestURL);
            webRequest.method = UnityWebRequest.kHttpVerbPOST;
            using UploadHandlerRaw uploadHandler = new(Encoding.ASCII.GetBytes(postData));
            webRequest.uploadHandler = uploadHandler;
            webRequest.downloadHandler = new DownloadHandlerBuffer();
            webRequest.disposeUploadHandlerOnDispose = true;
            webRequest.disposeDownloadHandlerOnDispose = true;
            webRequest.SetRequestHeader("Content-Type", "application/json");
         
            webRequest.SetRequestHeader("withCredentials", "true");
            yield return webRequest.SendWebRequest();
            HandleRequestResult(webRequest, error, success);
        }

        private void HandleRequestResult<T>(UnityWebRequest webRequest, Action<string> error, Action<T> success)
        {
            try
            {
                if (webRequest.result != UnityWebRequest.Result.Success)
                {
                    error?.Invoke(webRequest.responseCode + " " + webRequest.error);
                }
                else
                {
                    T response = JsonUtility.FromJson<T>(webRequest.downloadHandler.text);
                    success?.Invoke(response);
                }
            } catch(Exception ex)
            {
                Debug.LogError(ex.Message);
            }
          
        }
    }
}
3 Likes

Using Unity version 2021.3.6f1 here, using the command

public UnityWebRequest(string url, string method)

and after disposing the data by following, still memory leak is occurring.

            request.disposeUploadHandlerOnDispose = true;
            request.disposeDownloadHandlerOnDispose = true;
            request.Dispose();

Hi Cobatheon,
I have tried many ways to break it, but it just does not break for me. Could you please run this coroutine here and see if that works for you?

 public IEnumerator UnityWebRequestTestSimplePasses()
    {
        using UnityWebRequest webRequest = new("http://www.google.com", UnityWebRequest.kHttpVerbGET);
        webRequest.downloadHandler = new DownloadHandlerBuffer();
        webRequest.disposeUploadHandlerOnDispose = true;
        webRequest.disposeDownloadHandlerOnDispose = true;
        yield return webRequest.SendWebRequest();
        Debug.Log(webRequest.downloadHandler.text);
    }

For everyone else, if you struggle with UnityWebRequests, then there is a way more easy solution for you:

this way you can work with promises instead of coroutines which makes everything just a lot more easy. Everyone who works professionally with unity should use that package as it saves time and frustration ^^ :slight_smile: