How to release instantiated mesh correctly?

I have a code like the following. It will memory leak when switching scenes.

void OnWillRenderObject()
{
    if( MyAutoTileMap.TileAnimFrameHasChanged )
    {
        m_uv = m_meshFilter.mesh.uv;

        // Animated tiles
        float fTextTileWidth = (float)MyAutoTileMap.Tileset.TileWidth / MyAutoTileMap.Tileset.AtlasTexture.width;
        float offset = fTextTileWidth * MyAutoTileMap.TileAnim3Frame * 2;
        foreach( AnimTileData animTileData in m_animatedTiles )
        {
            m_uv[ animTileData.VertexIdx + 0 ].x = animTileData.U0 + offset;
            m_uv[ animTileData.VertexIdx + 1 ].x = animTileData.U0 + offset;
            m_uv[ animTileData.VertexIdx + 2 ].x = animTileData.U1 + offset;
            m_uv[ animTileData.VertexIdx + 3 ].x = animTileData.U1 + offset;
        }

        // waterfall tiles
        float fTextTilePartHeight = (float)MyAutoTileMap.Tileset.TilePartHeight / MyAutoTileMap.Tileset.AtlasTexture.height;
        foreach (AnimTileData animTileData in m_animatedWaterfallTiles)
        {
            int tilePartOff = (animTileData.SubTileRow + 4-MyAutoTileMap.TileAnim4Frame) % 4 - animTileData.SubTileRow;
            offset = -fTextTilePartHeight * tilePartOff;
            m_uv[animTileData.VertexIdx + 0].y = animTileData.V0 + offset;
            m_uv[animTileData.VertexIdx + 1].y = animTileData.V1 + offset;
            m_uv[animTileData.VertexIdx + 2].y = animTileData.V1 + offset;
            m_uv[animTileData.VertexIdx + 3].y = animTileData.V0 + offset;
        }

        m_meshFilter.mesh.uv = m_uv;
    }
}

 void OnDestroy()
{
    //avoid memory leak
    if (m_meshFilter != null && m_meshFilter.sharedMesh != null)
    {
        DestroyImmediate(m_meshFilter.sharedMesh);
        m_meshFilter.sharedMesh = null;
    }
}
}

If I mark the following two lines, then it won’t memory leak any more.

// m_uv = m_meshFilter.mesh.uv;
...
// m_meshFilter.mesh.uv = m_uv;

Is anything wrong in the OnDestroy() method? What I missing?

Unless you keep a reference to that mesh (such as in a static or a singleton), it should not be necessary to free it when changing scenes. When it no longer has references, Unity should clear it out at a scene change.

If it doesn’t, try using the memory profiler to see if you can figure out who is holding onto a reference to that mesh.

hmm… MyAutoTileMap is a singleton class indeed.
At end, I seems have found the solution by myself.
I create a new variable m_mesh to access m_meshFilter.mesh instead and destroy it on the OnDestroy method.
Then it seems no memory leak any more…
BTW, the code is from the TileChunk.cs in the RPG Map Editor plugin.

private Mesh m_mesh;
(skip)..........
void OnWillRenderObject()
{
    if( MyAutoTileMap.TileAnimFrameHasChanged )
    {
        m_uv = m_mesh.uv;
        (skip)........
        m_mesh.uv = m_uv;
    }
}
void OnDestroy()
{
    //avoid memory leak
    if (m_mesh != null)
    {
        DestroyImmediate(m_mesh);
    }
}
1 Like

In my experience meshes and stuff like render textures created during runtime doesn’t get cleaned automatically, you have to call Destroy on them

1 Like

Use the normal Destroy, the Immediate version can do some weird stuff sometimes and you have no reason to do so.