【问题标题】:Memory leak because of MapBox in Unity由于 Unity 中的 MapBox 导致内存泄漏
【发布时间】:2021-08-15 20:06:59
【问题描述】:

我在我的 Unity 项目中使用 MapBox SDK,我只是显示地图。我不使用方向等其他服务。不知何故,我总是收到一个错误,即存在内存泄漏。因为我的项目是一个 Ios 和 Android 应用程序,所以内存泄漏对我来说听起来不是那么好哈哈。

引用的错误是这样的:

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[])
Mapbox.Unity.Telemetry.<PostWWW>d__8:MoveNext() (at Assets\Mapbox\Unity\Telemetry\TelemetryEditor.cs:82)
Mapbox.Unity.Utilities.Routine:MoveNext() (at Assets\Mapbox\Unity\Utilities\Runnable.cs:130)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
UnityEngine.MonoBehaviour:StartCoroutineManaged2(IEnumerator)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
Mapbox.Unity.Utilities.Routine:.ctor(IEnumerator) (at Assets\Mapbox\Unity\Utilities\Runnable.cs:116)
Mapbox.Unity.Utilities.Runnable:Run(IEnumerator) (at Assets\Mapbox\Unity\Utilities\Runnable.cs:47)
Mapbox.Unity.Telemetry.TelemetryEditor:SendTurnstile() (at Assets\Mapbox\Unity\Telemetry\TelemetryEditor.cs:37)
Mapbox.Unity.MapboxAccess:ConfigureTelemetry() (at Assets\Mapbox\Unity\MapboxAccess.cs:196)
Mapbox.Unity.MapboxAccess:SetConfiguration(MapboxConfiguration, Boolean) (at Assets\Mapbox\Unity\MapboxAccess.cs:108)
Mapbox.Unity.MapboxAccess:LoadAccessToken() (at Assets\Mapbox\Unity\MapboxAccess.cs:161)
Mapbox.Unity.MapboxAccess:.ctor() (at Assets\Mapbox\Unity\MapboxAccess.cs:66)
Mapbox.Unity.MapboxAccess:get_Instance() (at Assets\Mapbox\Unity\MapboxAccess.cs:41)
Mapbox.Unity.Map.<SetupAccess>d__88:MoveNext() (at Assets\Mapbox\Unity\Map\AbstractMap.cs:609)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
UnityEngine.MonoBehaviour:StartCoroutineManaged(String, Object)
UnityEngine.MonoBehaviour:StartCoroutine(String, Object)
UnityEngine.MonoBehaviour:StartCoroutine(String)
Mapbox.Unity.Map.AbstractMap:MapOnStartRoutine(Boolean) (at Assets\Mapbox\Unity\Map\AbstractMap.cs:534)
Mapbox.Unity.Map.AbstractMap:Start() (at Assets\Mapbox\Unity\Map\AbstractMap.cs:500)

它指向 SDK 附带的 MapBox 脚本。我不知道是否应该在此处包含这些内容,因为我没有以任何方式接触它们,而且它们非常通用并且指向许多其他脚本。

有人知道吗?或者我可以忽略这一点,我的应用程序可以正常工作吗?到目前为止,据我所知,我没有任何测试问题。

感谢您与我一起思考!

【问题讨论】:

  • 文字表示Mapbox.Unity.Map.AbstractMap使用了一些非托管资源。 Ubiquotus 具有任何类型的高性能绘图或图像。必须使用对 Dispose 的调用来释放非托管资源。 |请向我们展示您如何创建实例以及在哪里(如果有的话)处理它。我通常的建议是:“创建。使用。处置。所有这些都在同一段代码中,最好使用 using 块。”但这可能是不可能的罕见情况。

标签: c# unity3d memory-leaks mapbox


【解决方案1】:

以下错误只会出现在编辑器中,不会影响定位平台,因为您的Assets/Mapbox/Unity/Telemetry/TelemetryEditor.cs 脚本中存在 UNITY_EDITOR 宏。

如果您仍想修复此错误,则必须在使用完 UnityWebRequest 对象后调用 Dispose,无论请求成功还是失败,只需将 PostWWW 方法替换为以下内容:

        IEnumerator PostWWW(string url, string bodyJsonString)
        {
            byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);

#if UNITY_2017_1_OR_NEWER
            using (UnityWebRequest postRequest = new UnityWebRequest(url, "POST"))
            {
                postRequest.SetRequestHeader("Content-Type", "application/json");

                postRequest.downloadHandler = new DownloadHandlerBuffer();
                postRequest.uploadHandler = new UploadHandlerRaw(bodyRaw);

                yield return postRequest.SendWebRequest();

                while (!postRequest.isDone) { yield return null; }

                if (!postRequest.isNetworkError)
                {
#else
                var headers = new Dictionary<string, string>();
                headers.Add("Content-Type", "application/json");
                headers.Add("user-agent", GetUserAgent());
                var www = new WWW(url, bodyRaw, headers);
                yield return www;

                while (!www.isDone) { yield return null; }

                // www doesn't expose HTTP status code, relay on 'error' property
                if (!string.IsNullOrEmpty(www.error))
                {
#endif
                    PlayerPrefs.SetString(Constants.Path.TELEMETRY_TURNSTILE_LAST_TICKS_EDITOR_KEY, "0");
                }
                else
                {
                    PlayerPrefs.SetString(Constants.Path.TELEMETRY_TURNSTILE_LAST_TICKS_EDITOR_KEY, DateTime.Now.Ticks.ToString());
                }
            }
        }

【讨论】:

  • 谢谢!那么,如果我说这个错误不会导致 Android 和 Ios 版本出现问题,我是否正确? :)
  • @RicardoFrederiks 不客气。是的,你是对的。
【解决方案2】:

文字表明 Mapbox.Unity.Map.AbstractMap 使用了一些非托管资源。这在任何处理图像或绘图的类中无处不在。我个人不知道这个类,但是这个名字一点也不奇怪。

GC 不会及时自动清理非托管资源。虽然通常有一个终结器来最终清理该资源,但通常没有等待的选择。在这种情况下,似乎还有一个例外可以确保您不会忘记 - 非常方便!

您的工作是确保在删除最后一个引用之前清理非托管资源,方法是调用Mapbox.Unity.Map.AbstractMap.Dispose()

每当您处理任何可处置的事情时,我的一般建议是:“创建。使用。处置。全部在同一段代码中,最好使用using statement。”通常建议重新设计您的代码,以便您可以尽可能地遵循该模式。

有一个非常罕见的例外。在这种极少数情况下,您必须实现 Dispose pattern

Dispose 模式有两个用例:

  • 您直接处理非托管资源。这基本上不会发生。类库已经涵盖了所有可能的情况。在这种情况下,您首先编写一个 Finalizer,然后为了方便添加一个 Dispose 函数
  • 您有一个实现 IDisposeable 的任何类型的字段。在这种情况下,您自己的类必须实现 IDisposeable。唯一的目的是将 Dispose() 调用中继到您的类型包含的任何 Disposeable 字段。这是 99% 的用例。

由于代码大部分是相同的,通常终结器是 Dispose(bool) 函数的一部分。 fianlizer 和 Dispose 之间的唯一区别是:

  • 终结器调用从不中继到 Disposeable 字段。 Finalizer 是每个 Instance 和 GC 之间的母体。
  • Dispose 调用总是中继到 Disposeable 字段。该中继实际上是您首先实施 IDisposeable 的唯一原因。

【讨论】:

  • 感谢您的信息!这里的问题是我没有在 Unity 中编写任何脚本来让 MapBox 工作。通过导入UnityPackage添加SDK后全部拖放。它都是通用的,很难理解(对我来说)完成工作的脚本。所以这就是为什么我必须处理一些东西对我来说很奇怪。如果我需要自己编写脚本并调用库,那么我知道我需要在代码中手动完成。这个之后的答案让我相信这个问题不需要解决,因为它只发生在编辑器中。 :)
  • @RicardoFrederiks 对我来说,这听起来像是有问题。您只能在编辑器中收到警告。你会忽略这个问题。
猜你喜欢
  • 2016-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2016-07-10
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
相关资源
最近更新 更多