unity-wakatime icon indicating copy to clipboard operation
unity-wakatime copied to clipboard

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

Open NachtgeistW opened this issue 3 years ago • 23 comments

This happened in 2021.1. Every time I press "Play" button, they appear in console. I used com.unity.jobs and caught these:

A Native Collection has not been disposed, resulting in a memory leak. Allocated from: Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator) UnityEngine.Networking.UploadHandlerRaw:.ctor(Byte[]) WakaTime.Plugin:SendHeartbeat(Boolean) (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:145) WakaTime.Plugin:OnSceneClosing(Scene, Boolean) (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:205) UnityEditor.SceneManagement.EditorSceneManager:Internal_SceneClosing(Scene, Boolean)

A Native Collection has not been disposed, resulting in a memory leak. Allocated from: Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator) UnityEngine.Networking.UploadHandlerRaw:.ctor(Byte[]) WakaTime.Plugin:SendHeartbeat(Boolean) (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:145) WakaTime.Plugin:Initialize() (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:62) WakaTime.Plugin:OnScriptReload() (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:181)

A Native Collection has not been disposed, resulting in a memory leak. Allocated from: Unity.Collections.NativeArray`1:.ctor(Byte[], Allocator) UnityEngine.Networking.UploadHandlerRaw:.ctor(Byte[]) WakaTime.Plugin:SendHeartbeat(Boolean) (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:145) WakaTime.Plugin:OnPlaymodeStateChanged(PlayModeStateChange) (at Library\PackageCache\com.vladfaust.unitywakatime@4dedbeac2e\Editor\Plugin.cs:185) UnityEditor.EditorApplication:Internal_PlayModeStateChanged(PlayModeStateChange) UnityEditor.EditorApplication:set_isPlaying(Boolean) Unity.Entities.Editor.LiveLinkToolbar:TogglePlaying() (at Library\PackageCache\[email protected]\Unity.Entities.Editor\LiveLink\LiveLinkToolbar.cs:94) Unity.Entities.Editor.LiveLinkToolbar:DrawPlaybar(CommandExecuteContext) (at Library\PackageCache\[email protected]\Unity.Entities.Editor\LiveLink\LiveLinkToolbar.cs:60) UnityEditor.CommandService:ExecuteCommand(String, CommandHint, Object[]) UnityEditor.CommandService:Execute(String, CommandHint, Object[]) UnityEditor.ModeService:Execute(String, CommandHint, Object[]) UnityEditor.ModeService:Execute(String, Object[]) UnityEditor.Toolbars.PlayModeButtons:OverrideGUIHandler() UnityEngine.UIElements.IMGUIContainer:DoOnGUI(Event, Matrix4x4, Rect, Boolean, Rect, Action, Boolean) UnityEngine.UIElements.IMGUIContainer:HandleIMGUIEvent(Event, Matrix4x4, Rect, Action, Boolean) UnityEngine.UIElements.IMGUIContainer:HandleIMGUIEvent(Event, Action, Boolean) UnityEngine.UIElements.IMGUIContainer:HandleIMGUIEvent(Event, Boolean) UnityEngine.UIElements.IMGUIContainer:SendEventToIMGUIRaw(EventBase, Boolean, Boolean) UnityEngine.UIElements.IMGUIContainer:SendEventToIMGUI(EventBase, Boolean, Boolean) UnityEngine.UIElements.IMGUIContainer:HandleEvent(EventBase) UnityEngine.UIElements.CallbackEventHandler:HandleEventAtTargetPhase(EventBase) UnityEngine.UIElements.MouseCaptureDispatchingStrategy:DispatchEvent(EventBase, IPanel) UnityEngine.UIElements.EventDispatcher:ApplyDispatchingStrategies(EventBase, IPanel, Boolean) UnityEngine.UIElements.EventDispatcher:ProcessEvent(EventBase, IPanel) UnityEngine.UIElements.EventDispatcher:ProcessEventQueue() UnityEngine.UIElements.EventDispatcher:OpenGate() UnityEngine.UIElements.EventDispatcherGate:Dispose() UnityEngine.UIElements.EventDispatcher:ProcessEvent(EventBase, IPanel) UnityEngine.UIElements.EventDispatcher:Dispatch(EventBase, IPanel, DispatchMode) UnityEngine.UIElements.BaseVisualElementPanel:SendEvent(EventBase, DispatchMode) UnityEngine.UIElements.UIElementsUtility:DoDispatch(BaseVisualElementPanel) UnityEngine.UIElements.UIElementsUtility:UnityEngine.UIElements.IUIElementsUtility.ProcessEvent(Int32, IntPtr, Boolean&) UnityEngine.UIElements.UIEventRegistration:ProcessEvent(Int32, IntPtr) UnityEngine.UIElements.<>c:<.cctor>b__1_2(Int32, IntPtr) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

NachtgeistW avatar Apr 25 '21 12:04 NachtgeistW

Same here, its leaking memory

HaipaDev avatar Jun 13 '21 14:06 HaipaDev

I can guess that UploadHandlerRaw shall be disposed properly @ https://github.com/vladfaust/unity-wakatime/blob/72a78455940c4585bb2ed3fe491527898adf4148/Assets/com.vladfaust.unitywakatime/Editor/Plugin.cs#L145

vladfaust avatar Jul 21 '21 13:07 vladfaust

I think the UnityWebRequest.Post needs to ~~be wrapped in a using statement so that it disposes correctly~~ have Dispose called manually in the completed callback.

I am pretty sure the native collection leak is something which only happens on more recent unity versions, as it is not a problem on pre 2021 versions from what I saw

I can go make a PR with fixes in if needed :)

JayPeet avatar Nov 19 '21 18:11 JayPeet

PR is here: https://github.com/vladfaust/unity-wakatime/pull/31

JayPeet avatar Nov 19 '21 19:11 JayPeet

This bug is still happening and causing constant error messages in Unity. Can someone approve the PR that JayPeet created to fix this?

BrianLDev avatar Feb 06 '22 08:02 BrianLDev

@BrianLDev

Actually, this sometimes still has the issue.

vladfaust avatar Feb 06 '22 08:02 vladfaust

Ah that's a shame. The error messages were getting annoying and I was hoping this would fix it.

BrianLDev avatar Feb 07 '22 00:02 BrianLDev

Yeah, I need to investigate it properly still. Just been too busy :(

JayPeet avatar Feb 07 '22 01:02 JayPeet

I'm not a Unity developer anymore. At least for now. Would be happy if someone takes over this repository. @Hermesiss?

vladfaust avatar Feb 09 '22 07:02 vladfaust

Yes, I'm still an active Unity developer. @vladfaust can you transfer this repo to me?

Hermesiss avatar Feb 10 '22 08:02 Hermesiss

@Hermesiss let's begin with fixing this issue (you're a collaborator) 😃

vladfaust avatar Feb 10 '22 22:02 vladfaust

@JayPeet @NachtgeistW @HyperGamesDev Can you provide an example project? I can't reproduce this error

Hermesiss avatar Feb 14 '22 05:02 Hermesiss

my repository SSS222 had WakaTime before, sorry for the inconvenience but you'd have to add it once again now as I removed it(also the Jobs addon). Not sure when it appeared though so it may be difficult to reproduce

HaipaDev avatar Feb 14 '22 12:02 HaipaDev

It's about Unity Engine

public UnityWebRequestAsyncOperation SendWebRequest() in class UnityWebRequest Begin communicating with the remote server. External documentation for UnityWebRequest.SendWebRequest

If this operation can be replaced for other the problem will be solved.

for example, if you use the obsolete: Method 'UnityEngine.Networking.UnityWebRequest.Send' is obsolete: Use SendWebRequest. It returns a UnityWebRequestAsyncOperation which contains a reference to the WebRequest object.

The leak disapear.

HermesZum avatar Feb 27 '22 01:02 HermesZum

Hello! Curious if this has been investigated yet.

hs-pp avatar May 18 '22 23:05 hs-pp

I think I managed to reduce the number of warnings.

But the

static void OnPlaymodeStateChanged(PlayModeStateChange change) {
      SendHeartbeat();
    }

still throws an error when the editor begin the Play, but not always.

If you test this snippet, tell me how it went, so that it can be improved:

Plugin.cs

static void SendHeartbeat(bool fromSave = false) 
    {
      var currentScene = EditorSceneManager.GetActiveScene().path;
      var file = currentScene != string.Empty
        ? Application.dataPath + "/" + currentScene.Substring("Assets/".Length)
        : string.Empty;
      var heartbeat = new Heartbeat(file, fromSave);
      var heartbeatJSON = JsonUtility.ToJson(heartbeat);
      var request = UnityWebRequest.Post(URL_PREFIX + "users/current/heartbeats?api_key=" + _apiKey, string.Empty);
      request.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(heartbeatJSON));
      request.SetRequestHeader("Content-Type", "application/json");

      request.SendWebRequest().completed +=
        operation => 
        {
          if (_debug) Debug.Log("<WakaTime> Sending heartbeat...");
          
          if ((heartbeat.time - _lastHeartbeat.time < HEARTBEAT_COOLDOWN) && !fromSave &&
              (heartbeat.entity == _lastHeartbeat.entity)) 
          {
            if (_debug) Debug.Log("<WakaTime> Skip this heartbeat");
            request.Dispose();
            return;
          }
          
          if (request.downloadHandler.text == string.Empty) 
          {
            Debug.LogWarning(
              "<WakaTime> Network is unreachable. Consider disabling completely if you're working offline");
            request.Dispose();
            return;
          }
          
          if (_debug)
            Debug.Log("<WakaTime> Got response\n" + request.downloadHandler.text);
          
          var response =
            JsonUtility.FromJson<Response<HeartbeatResponse>>(
              request.downloadHandler.text);

          if (response.error != null) 
          {
            if (response.error == "Duplicate") 
            {
              if (_debug) Debug.LogWarning("<WakaTime> Duplicate heartbeat");
              request.Dispose();
            }
            else 
            {
              Debug.LogError(
                "<WakaTime> Failed to send heartbeat to WakaTime!\n" +
                response.error);
              request.Dispose();
            }
          }
          else 
          {
            if (_debug) Debug.Log("<WakaTime> Sent heartbeat!");
            _lastHeartbeat = response.data;
            request.Dispose();
          }
        };
    }

HermesZum avatar Jun 29 '22 23:06 HermesZum

The easiest fix i found was to go to the PlayFabEditorHttp script, go the the Post coroutine method, and add www.Dispose(); at the end of the method

celojevic avatar Jul 22 '22 12:07 celojevic

Since this problem still isn't fixed, I decided to create my own plugin. Used this one as example, but I started from zero in order to create better readable code. At the risk of being flamed for shameless advertising, https://github.com/vanBassum/Wakatime.Unity :)

Please give it a try, and let me know if anything needs tweaking.

vanBassum avatar Sep 09 '22 09:09 vanBassum

I've added your repo to the Unity page on WakaTime's website:

https://wakatime.com/unity

alanhamlett avatar Sep 09 '22 10:09 alanhamlett

Awesome, thanks

vanBassum avatar Sep 09 '22 10:09 vanBassum

Since this problem still isn't fixed, I decided to create my own plugin. Used this one as example, but I started from zero in order to create better readable code. At the risk of being flamed for shameless advertising, https://github.com/vanBassum/Wakatime.Unity :)

Please give it a try, and let me know if anything needs tweaking.

Thank you!

NachtgeistW avatar Sep 12 '22 08:09 NachtgeistW

@alanhamlett Can we remove the link to vladfaust's version of unity wakatime from Wakatime's website? This bug has been unresolved for 1.5 years and there are better alternatives without the bug. Or at least put the link at the bottom of the list with a note that it has unresolved bugs.

BrianLDev avatar Sep 12 '22 19:09 BrianLDev

Bump? This still seems to happen in 2023.2.3f1

MelvinKuhlmann avatar Feb 11 '24 00:02 MelvinKuhlmann