记录一下解决 Unity A Native Collection has not been disposed 错误的要点

其实这个错误,也有很多文章说了,但是光看文章,你还真的不一定能解决的了,所以才困扰了我很久。

第一步先说怎么定位有问题的地方,Unity编辑器其实有一个隐藏的内存泄露检测模式的功能,可以把这个错误的所在堆栈给打印出来,这里提供一段代码来启用这个功能。

using Unity.Collections;
using UnityEditor;

/// 
/// 内存泄露检测模式
/// 
public class LeakDetectionMode
{
    [MenuItem("Jobs/内存泄漏检测/显示当前模式")]
    static void ShowLeakDetection()
    {
        string message = string.Format("当前模式: {0}", NativeLeakDetection.Mode.ToString());
        EditorUtility.DisplayDialog("内存泄漏检测模式", message, "OK");
    }
    
    
    [MenuItem("Jobs/内存泄漏检测/禁用")]
    static void LeakDetectionDisable()
    {
        NativeLeakDetection.Mode = NativeLeakDetectionMode.Disabled;
    }

    // 验证方法会在正式方法前执行,通不过就会置灰
    [MenuItem("Jobs/内存泄漏检测/禁用", true)]
    static bool ValidateLeakDetectionDisable()
    {
        return NativeLeakDetection.Mode != NativeLeakDetectionMode.Disabled;
    }
    
    
    [MenuItem("Jobs/内存泄漏检测/启用")]
    static void LeakDetectionEnabled()
    {
        NativeLeakDetection.Mode = NativeLeakDetectionMode.Enabled;
    }
    
    [MenuItem("Jobs/内存泄漏检测/启用", true)]
    static bool ValidateLeakDetectionEnabled()
    {
        return NativeLeakDetection.Mode != NativeLeakDetectionMode.Enabled;
    }

    
    [MenuItem("Jobs/内存泄漏检测/启用堆栈跟踪")]
    static void LeakDetectionEnabledWithStackTrace()
    {
        NativeLeakDetection.Mode = NativeLeakDetectionMode.EnabledWithStackTrace;
    }

    [MenuItem("Jobs/内存泄漏检测/启用堆栈跟踪", true)]
    static bool ValidateLeakDetectionEnabledWithStackTrace()
    {
        return NativeLeakDetection.Mode != NativeLeakDetectionMode.EnabledWithStackTrace;
    }
}

我们使用其中的“启用堆栈跟踪”选项,就能看到这个报错的堆栈信息了。

然后我们就可以发现,出错的地方在 UnityWebRequest 上,经过一通查询,发现最多的说法是,申请的 request 没有回收导致的内存泄露,解决方法很简单,就是添加一下 using 关键字。

就在我以为已经大功告成的时候,结果发现控制台里,这个错误依旧还在,这就叫人很无奈了。

经过一通测试和多日和代码的朝夕相处,终于发现了问题的关键。

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

我们有的时候,会设置自己的 uploadHandler ,但是不设时,request 自己原本也有一个的,它就不会被释放了,自然是要泄露了。

且 request 在回收后,并不代表 handler 就会自动跟着一起回收的,我们需要对 request 进行相应的设置才行。

request.disposeUploadHandlerOnDispose = true;
request.disposeDownloadHandlerOnDispose = true;
request.disposeCertificateHandlerOnDispose = true;

当我们把能设置的地方设好,能回收的对象都确保回收后,之前常驻在控制台中的错误

A Native Collection has not been disposed 

它终于消失掉了。

你可能感兴趣的:(Unity,UnityWebRequest,Unity,内存泄露,尚未释放的原生集合)