Help Needed , Garbage collector Never activates and application eventually freezes computer[Solved]

Hello all , so a little background , im making a Voxel terrain engine for my game , I use a LOD system and I have to regenerate the terrain when the player moves , Now I pool everything , The gameobjects ,the meshes , the 3d array used for the voxel values , trees etc .I create my mesh using unitys new meshdata and meshData array in another thread like so on my own thread

 public void CreateMyMesh()
        {
            int size = verts.Count;
            int T = tris.Count;
            var m = meshData[0];
            m.SetVertexBufferParams(size, new VertexAttributeDescriptor(VertexAttribute.Position, stream: 0), new VertexAttributeDescriptor(VertexAttribute.Normal, stream: 1), new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4, 2), new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2, 3));
            m.SetIndexBufferParams(T, IndexFormat.UInt32);


            NativeArray<Vector3> NVerts;
            NVerts = meshData[0].GetVertexData<Vector3>(0);

            NativeArray<Vector3> NNormals;
            NNormals = meshData[0].GetVertexData<Vector3>(1);

            NativeArray<Color> NColors;
            NColors = meshData[0].GetVertexData<Color>(2);

            NativeArray<Vector2> NUVs;
            NUVs = meshData[0].GetVertexData<Vector2>(3);

         




            NativeArray<int> NTris;
            NTris = m.GetIndexData<int>();

            int vCount = NVerts.Length;


            for (int i = 0; i < vCount; i++)
            {

                NVerts[i] = verts[i];
                NNormals[i] = normals[i];
                NColors[i] = colorsM[i];
                NUVs[i] = Uvs[i];

            }
            for (int i = 0; i < T; i++)
            {
                NTris[i] = tris[i];
            }
            var sm = new SubMeshDescriptor(0, T, MeshTopology.Triangles);
            sm.firstVertex = 0;
            sm.vertexCount = size;
         
            m.subMeshCount = 1;

            m.SetSubMesh(0, sm);
            NVerts.Dispose();
            NColors.Dispose();
            NUVs.Dispose();
            NNormals.Dispose();
            NTris.Dispose();
            verts = null;
            tris = null;
            normals = null;
            colorsM = null;
            Uvs = null;
        }

Then in the main thread I Do this

//this object is pooled so I dont actually create a new mesh here its just for the explanation
mesh = new Mesh();
Mesh.ApplyAndDisposeWritableMeshData(meshData, m_voxelGo.mesh, MeshUpdateFlags.Default);

If i dont call this last part memory usage never increases beyond initial usage.
So everything runs fine if I dont create a unity mesh object , i can create and destroy the chunks and the lists of triangles vertices, normals, colors and uvs , but as soon as i assign those to a mesh or create the mesh unity memory usage climbs up and never drops , if I stand still the memory usage stays stable , but moving cause regeneration and the memory usage climbs up again until eventually my computer freezes , I can call GC.Collect and that works but I have to call it After each mesh creation otherwise the game will eventually freeze , this would be great except it freezes unity everytime i call gc.Collect.

Now my question is why is there so much garbage being created when creating a mesh ? and why is unity not doing garbage collection automatically , I looked on the profiler and GC.collect is never called , garbage is created but never collected , I did also check to see if maybe the meshes were being leaked and the number of meshes never increases beyond initial creation . Thanks for reading my long winded explanation

Could it be a bug in your pooling system that you are constantly creating new objects / meshes and constantly increasing your pool instead of reusing old ones?

Thanks for your reply , I did think of that , but the mesh count never increases , also tried just destroying the meshes instead of pooling and it made no difference .

In general, if the memory grows and the gc does not clear up, that means that there is still a reference to objects somewhere.

Perhaps you should also post the code where the methods are called. E.g. how you initialize the Mesh objects or how you get the meshdata.

1 Like

ok so heres my reusable Object code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VoxelEngine;
using UnityEngine.AI;
public class VoxelGO : MonoBehaviour
{
    // Start is called before the first frame update
    public NavMeshSourceTag sourceTag;
    public MeshCollider m_MeshCollider;
    public GameObject myGameObject;
    public Transform m_Transform;
    public Vector3 m_pos;
    public Mesh mesh;
    public bool CanRender;
    public static int layer;
    public void Update()
    {
        if (CanRender)
        {
            Graphics.DrawMesh(mesh, m_pos, Quaternion.identity,VoxelTerrainEngine.Generator.m_material, layer, null, 0, null, true, true);
        }
    }
}

The return to Pool Code ,

        public void Destroy() {
//isupperlevel == TreeObject
            if (isUpperLevel == false)
            {
                canGrass = false;

                if (m_voxelGo != null )
                {
                    m_voxelGo.myGameObject.SetActive(false);
                    generator.GOChunkPool.Enqueue(m_voxelGo);
                    m_voxelGo.CanRender = false;
                    m_voxelGo.mesh.Clear();
                    m_voxelGo.sourceTag.UnMake();

                }
                HasMesh = false;
}

The request Code

                    if (m_voxelGo == null)
                    {
                        m_voxelGo = generator.RequestVoxelGo();



                    }
                    else m_voxelGo.sourceTag.UnMake();
                    // m_mesh.AddComponent<NavMeshSourceTag>();



                    //


                    m_voxelGo.m_Transform.localPosition = m_pos;

                    if (m_voxelGo.mesh == null)
                    {

                        m_voxelGo.mesh = new Mesh();
                        m_voxelGo.mesh.MarkDynamic();
                    }
                    else
                    {
                        m_voxelGo.mesh.Clear();
}
                    Mesh.ApplyAndDisposeWritableMeshData(meshData, m_voxelGo.mesh, MeshUpdateFlags.Default);
                    m_voxelGo.mesh.RecalculateBounds();
                    m_voxelGo.myGameObject.SetActive(true);
                    m_voxelGo.m_pos = m_pos;
                    m_voxelGo.CanRender = true;
                    m_voxelGo.sourceTag.mesh = m_voxelGo.mesh;
                    m_voxelGo.sourceTag.myTransform = m_voxelGo.m_Transform;

                    m_voxelGo.sourceTag.Make();

                    }

and finally the Function To request a voxelGo Object

public ConcurrentQueue<VoxelGO> GOChunkPool = new ConcurrentQueue<VoxelGO>();
       public VoxelGO RequestVoxelGo()
        {
            VoxelGO Go;

            if (GOChunkPool.TryDequeue(out Go))
                return Go;
            else
            {
                GameObject gameo = new GameObject();
                Go = gameo.AddComponent<VoxelGO>();

                Go.m_MeshCollider = gameo.AddComponent<MeshCollider>();
                Go.myGameObject = gameo;
                Go.m_Transform = gameo.transform;
                Go.m_Transform.parent = parent;
                Go.sourceTag = gameo.AddComponent<NavMeshSourceTag>();
                Go.tag = parent.tag;
                gameo.SetActive(false);
                if (poolsFilled)
                    Debug.Log("Added new Go" + GOChunkPool.Count);
            }
            return Go;

        }

Also activating the garbage collector manually works and clears memory, so clearly there is garbage to collect , my guess is maybe it just doesnt activate due to some bug in unity itself , I am using onboard graphics so maybe unity is counting my onboard memory as available system memory so the gc never activates ?

Edit Also my main question was why is creating a mesh making so much garbage if I create 250 meshes thats 500mb of garbage that gets created ,only when creating meshes

If i create 250 empty meshes, Unity alloc only 9,8 KB GC memory. How many vertices do you have per mesh?

Who actually manages m_voxelGo? do you only ever have one VoxelGO visible at the same time (then a pool wouldn’t make much sense.)?

Have you debugged the code and checked that RequestVoxelGo() is not constantly creating new Gamobjects and that Destroy() never returns anything? You should also see that when the number of game objects in the hierarchy is constantly increasing.

I recently noticed a similar problem, I’ve created tons of class instances in a loop and didn’t use them, just to see how Unity behaves in comparison to .NET5. Unity quickly used up my system RAM (32GB). NET5 stayed constant at 42MB.

1 Like

interesting maybe that has something to do with it , my voxelchunk class has over 2500 instances at any given time , they are pooled as well , maybe thats where the garbage is coming from, but as I said without creating a mesh and just creating everything else my memory stays the same all the time , due to me rendering my grass using graphics.draw I can see that the chunks are being made and destroyed due to grass being on Lod 0.

Yes Ive debugged all pools , at start i fill the pools up so I reduce memory fragmentation , and in moving around which should use more pooled objects I never run out , I fill it with 200 of each, added debug.logs to any allocations after the pool is full, after wondering around I had maybe 1 or 2 new instances but no more than that , as each new chunk is created if it has a mesh IE vertices.count > 0 then itll request a voxelGO from the pool otherwise itll just be data , only LOD0 data is kept the rest is returned to the pool after mesh creation.

I usually have maybe 1500 to 3000 vertices per chunk maybe at most 5000, theres also colors, normals , Tris and UVs unity says each mesh only ever uses roughly 200KB each according to the mesh inspector , 200 - 250 meshes with 200kb each .

Again thanks for your help so far I might try going to a different .Net version since this problem only showed up after upgrading to unity 2020.3 Im guessing something is messed up as 2020.1 was working well but cant be sure as my code changed a bit since that version , but maybe .Net is broken in unity .

One think you can try is to tun off/on Incremental Garbage collection, and see if it behaves differently.

tried changing every setting , seems i was wrong about unitys mesh class causing problem ,unfortunatly it looks like even just creating voxelchunks with nothing in them results in over 1gb of GC allocation , so seems unity is either broken or I somehow have over 1Gb of data being created I dont know about , So for now I’ll have to wait, At any one time I have over 3000 voxelchunks , even with nothing in them and no voxel data being processed it still uses 1GB of memory GC alloc just to reuse these objects ,which are also pooled so Im stumped , only thing stored in these chunks is null lists (empty uninitialized lists) and 2 strings with 10 characters each.
But whats wierd is that the memory is all garbage , so Im not sure where this garbage is being made .

This sounds like a task for the memory profiler. You an use it to capture a memory snapshot and get a full list of every object in memory.

Sadly the memory profiler doesn’t seem to capture multithreaded information .

How do you save the data of the voxels? if you have the voxel as scruct and use a C# array, then you always allocate the full voxel memory as soon as the array is created with new. Then it is also important how many bytes per voxel?

1 Like

Yes they are structs 1 float for voxelvalue and 2 byte for material and biome values and are requested from the pool only when setting the voxel values with noise , under 2 conditions they are put back into the pool lod >0 or is completly empty or is completly full with no empty spaces . Still the issue of garbage creation exists even with out requesting the voxels , so I’m still confused by it .

The voxels are stored in a 3d array like so voxels [,] m_voxels . And left as null till requested from the engine

The voxel data shouldn’t be a problem unless you have huge chunks.
Have you ever tried to generate a single chunk on the mainthread for memory profiling?

1 Like

Thats a good idea I’ll try that gonna turn off garbage collection if I can just to test it cause it might disapear to fast for me to see but thanks ill take a look

ok ive done snapshot of before and after but i have no idea how to even interpret the memory profiler for garbage , it all just mostly looks like like gibberish to me , i did notice 5 allocations of 4.3mb of a large allocation but no reference or anything so i have no way of knowing whether thats it or not , nothing in the memory profiler about garbage or voxelchunk so Im not sure

ok so I created 4 voxel chunks , stored them in an array , but they dont show up on the memory profiler , they only show up once with one reference and its a 54kb file with 0 bytes allocated 0 bytesfield target and I cant see the rest cause the memory profiler is broken and the other fields are blank due to some error in the profiler . anyway Im shelving it thanks for your help all was worth a shot