Unity中如何释放内存?

Posted

技术标签:

【中文标题】Unity中如何释放内存?【英文标题】:How to release memory in Unity? 【发布时间】:2020-10-02 15:33:41 【问题描述】:

我看到,当我在 Unity 中在每一帧 (30fps) 上创建网格和纹理时,感觉就像 Unity 在使用后不会从内存中释放这些数据。

这是我的代码

private bool UpdateFrame(int frameIdx)
    
        bool result = true;
        int readyBuffSize = DecoderAPI.stream_get_ready_buffer_size(m_stream);

        if (m_currMeshFrameIndex != frameIdx
            && readyBuffSize > 0)
        
            m_currMeshFrameIndex = frameIdx;

            IntPtr frame = DecoderAPI.stream_get_next_frame_obj(m_stream);

            if (frame == IntPtr.Zero)
            
                result = false;
            
            else
            
                long sequentialFrameIdx = DecoderAPI.get_sequential_number(frame);
                DebugMethod("UNITY UpdateFrame", $"readyBuffSize :: readyBuffSize");
                DebugMethod("UNITY UpdateFrame", $"sequentialFrameIdx :: sequentialFrameIdx");

                Mesh releaseFormer = m_meshFilter.mesh;
                m_meshFilter.mesh = CrteateMesh(frame);
                Texture2D texture = CreateTexture(frame);
                m_meshRenderer.material.SetTexture("_MainTex", texture);

                DecoderAPI.stream_release_frame_obj(m_stream, frame);
                Destroy(releaseFormer);  // does not seem to help: even when there are no more allocations in C++ the process grows endlessly
            
        

        return result;
    

private Mesh CrteateMesh(IntPtr frame)
    
        Mesh mesh = new Mesh();

        //Vertices***
        int vertexCount = DecoderAPI.frame_get_vertex_count(frame);
        byte[] xyzBytes = new byte[vertexCount * 3 * 4];
        IntPtr xyz = DecoderAPI.frame_get_vertex_xyz(frame);
        Vector3[] vertices = new Vector3[vertexCount];

        GCHandle handle = GCHandle.Alloc(vertices, GCHandleType.Pinned);
        IntPtr pointer = handle.AddrOfPinnedObject();
        Marshal.Copy(xyz, xyzBytes, 0, xyzBytes.Length);
        Marshal.Copy(xyzBytes, 0, pointer, xyzBytes.Length);
        handle.Free();

        mesh.vertices = vertices;
        //***

        //Faces***
        int faceCount = DecoderAPI.frame_face_count(frame);
        int trisArrSize = faceCount * 3;
        int[] tris = new int[trisArrSize];
        IntPtr indices = DecoderAPI.frame_face_indices(frame);
        Marshal.Copy(indices, tris, 0, trisArrSize);
        mesh.triangles = tris;
        //***

        mesh.RecalculateNormals();

        //UV***
        int uvCount = DecoderAPI.frame_get_uv_count(frame);
        IntPtr uvData = DecoderAPI.frame_get_uv_data(frame);
        int uvArrSize = uvCount * 2;
        float[] uvArr = new float[uvArrSize];
        Vector2[] uv = new Vector2[uvCount];
        Marshal.Copy(uvData, uvArr, 0, uvArrSize);

        for (int i = 0; i < uvCount; i++)
        
            Vector2 result = new Vector2(uvArr[i * 2], uvArr[i * 2 + 1]) * new Vector2(1, -1);
            uv[i] = result;
        

        mesh.uv = uv;
        //***

        if (vertexCount != uvCount)
        
            long frameId = DecoderAPI.get_sequential_number(frame);
            DebugMethod("UNITY CrteateMesh", $"HERE : in frame id :: frameId, vertexCount : vertexCount, uvCount : uvCount");
        

        return mesh;
    

private Texture2D CreateTexture(IntPtr frame)
    
        IntPtr textureObj = DecoderAPI.frame_get_texture_obj(frame);
        DecoderAPI.TextureInfo textureInfo = DecoderAPI.texture_get_info(textureObj);

        int width = textureInfo.width;
        int height = textureInfo.height;
        int channels = textureInfo.channels;
        int stride = textureInfo.stride;

        //DecoderAPI.ColorType colorType = textureInfo.color_type;

        IntPtr pixels = textureInfo.pixels;
        Texture2D texture = new Texture2D(width, height, TextureFormat.RGB24, false);
        //Texture2D texture = new Texture2D(width, height, TextureFormat.DXT5, false);
        texture.LoadRawTextureData(pixels, width * channels * height);
        texture.Apply();

        return texture;
    

所以,我所做的是 - 我为使用它的每一帧创建一个网格和纹理,然后我希望 Unity 应该在使用后将它们从内存中释放,但不是。好的,我发现这种方法Destroy(releaseFormer) 应该会有所帮助,但无论如何我在TaskManager 中看到内存无限增长是一样的......

对于我已经尝试过的测试 -> 我开始生成我的 c++ 代码(比如说 100 帧)然后我停止它(所以我的 c++ 没有分配任何内容)并且我仍然看到内存增长到最后。我期望的是 - 好吧,即使 Unity 不释放我不需要的数据,我加载了 100 帧就是这样,为什么内存继续增长?

问题是 - 如何从内存中释放我不需要的所有帧?

编辑

我改变了这个方法,按正确的顺序添加了Destroy

private bool UpdateFrame(int frameIdx)
    
        bool result = true;
        int readyBuffSize = -1;

        if (m_stream != IntPtr.Zero)
        
            readyBuffSize = DecoderAPI.stream_get_ready_buffer_size(m_stream);
        

        if (m_currMeshFrameIndex != frameIdx
            && readyBuffSize > 0)
        
            m_currMeshFrameIndex = frameIdx;

            IntPtr frame = DecoderAPI.stream_get_next_frame_obj(m_stream);

            if (frame == IntPtr.Zero)
            
                result = false;
            
            else
            
                long sequentialFrameIdx = DecoderAPI.frame_get_sequential_number(frame);
                DebugMethod("UNITY UpdateFrame", $"readyBuffSize :: readyBuffSize");
                DebugMethod("UNITY UpdateFrame", $"sequentialFrameIdx :: sequentialFrameIdx");

                if (m_meshFilter.mesh != null)
                
                    Destroy(m_meshFilter.mesh);
                

                m_meshFilter.mesh = CrteateMesh(frame);

                if (m_texture != null)
                
                    Destroy(m_texture);
                

                m_texture = CreateTexture(frame);
                m_meshRenderer.material.SetTexture("_MainTex", m_texture);

                if (m_stream != IntPtr.Zero)
                
                    DecoderAPI.stream_release_frame_obj(m_stream, frame);
                
            
        

        return result;
    

【问题讨论】:

【参考方案1】:

releaseFormer 是网格对吗?您是否尝试在纹理对象本身上调用 Destroy?

另一个线程建议 Resources.UnloadUnusedAssets()

我个人会尝试使用 RenderTexture 来做到这一点,特别是如果纹理大小不会经常变化,但可能不适用于您的用例

【讨论】:

实际上我注意到,在我为纹理添加Destroy 之后,它显着改善了内存释放,但无论如何我看到它增长了一点。假设 1 分钟内达到 1Gb...如果您有任何我很高兴知道的建议,我会编辑我的问题。

以上是关于Unity中如何释放内存?的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D移动端内存优化(NGUI方面)

解决切换场景时NGUI图集资源未释放的问题

unity实战之lol技能释放范围

如何手动释放Linux内存?

解析PHP中的内存管理,PHP动态分配和释放内存

如何手动释放Linux内存的方法