C#/Unity Stack size and memory leaks

Hello everybody !

I would like to have a few advices on how to fix a problem I already have searched a lot about. Any help would be very appreciated :slight_smile:

I’m trying to implement the marching cubes algorithm in C# in Unity, running on grid of size 128**3. The calculation must be done at runtime and has to be instantaneous. I’m developing a toolbox to visualize scientific/molecular data, so I have to generate a lot of surfaces on user demand. To obtain a fast calculation I implemented a recursive version of the algorithm. That’s ok the calculation is always done < 30-40 ms even on ~old computer.

BUT I have 2 problems :

  • Insane memory leaks, due to the memory I have to use during each run of marching cubes and it is obviously not released/freed
  • Stack overflow exceptions, maybe due to stack size restrictions or wrong auto adaptation, but I HAVE to do this using recursion and have a large stack size

1) Memory leaks

I have a class MarchingCubesRec.cs that executes the work and call another script to generate the final GameObject(s) using the generated mesh. I’m calling it like this :

Main Script

MarchingCubesRec MCInstance; // global
MCInstance = new MarchingCubesRec(); // at start
MarchingCubesRec.MCRecMain(my_arguments); // in function, on user demand


GenerateMesh GMInstance; // global
GMInstance = new GenerateMesh(); // at MCRecMain call
// Do the mesh calculation, using only global variables initialized at function call
GenerateMesh.GM(my_other_arguments); // when mesh calculation finished, GM does GameObject(s) construction
//variables are used the same way than the 2 scripts before

That’s the way I build each GameObject composing my surface. I’m new to C# and I don’t really know if it’s the good way to call functions. I also tried static types for both variables and/or functions and other organizations of my code, but each time I generate a surface and create a GameObject my memory is increasing until I get an Out of memory Exception. I have to precise that only one surface is displayed at a time and it never takes more than 5-10 GameObjects. Previously generated GameObjects are destroyed using Destroy() at the same time than the new ones are created.

Does anybody knows WHY my memory is never freed ?
In fact I seems that 5-10% of allocated space is freed, from times to times. But I always end up with a few GB of memory used within a short time of utilization. I read a bit about the garbage collector handling of memory and I understood that recursion can sometimes prevent a normal (=“efficient” ?) garbage collection.
Then, does anybody knows HOW am I censed to handle this ?

2) Stack overflow exceptions

To perform my mesh calculation I use a recursive version of the marching cubes algorithm. My grid size is 128**3 (~2 millions points), so I understood that it’s normal to have a large stack size for this kind of thing. I’m sure my recursion is not infinite. The problem is I tried to use the Thread class to force a stack size that fits my needs, but I couldn’t generate the mesh while the new thread is not the main thread. Next step I want to try is recuperate the arguments from the calculation thread and then generate mesh on main thread.
Do you think that could solve my stack overflow exception problem ?

Thanks a lot for your help, you’re awesome, and I’ve been struggling on this for really too long :frowning:

Wow, you’ve stretched both Unity and C# to their limits… well done! :slight_smile:


First thing to do is call the GC yourself every let’s say 10 or 20 frames and see what happens:

  • If the memory problem persists, that means the problem is in your code - you are keeping references to objects somewhere so the GC can’t reclaim them. The only solution here is to go over the code with a fine comb, isolate individual parts of the code and test them individually, and so on until you find the leak.
  • If the memory problem goes away, that means you are just creating a lot of objects, faster than the GC can reclaim (this is very unlikely tough). Solution to this is to go over your code and see where you can try and reuse memory. for example use a List<> instead of allocating arrays, give it a big seed and reuse it. etc.

Generally speaking memory and GC in the C# env is a big topic in itself and I suggest you seek further help on this topic outside the Unity community as this is a general problem. You can get a lot of help on Stack Overflow, and picking up a good book on C# advanced topics will also help you.

One thing worth mentioning - bear in mind that a “destroyed” object from Unity’s point of view isn’t “destroyed” from C# point of view! Also unity overloads the == operator to return null if an object is destroyed in unity (but the references still exists in C#). Watch out for that.

Stack Overflow

There is less I can think of here, I’ve never had to deal with huge stack algorithms. The only thing I can think of is “are you sure you need recursion?”. Would it possible to implement the algorithm with Stack<> or a Queue<> instead?


I was faced with the problem of stack overflow too and the solution was to rewrite the marcher as a iterative algorithm. This can easily be done with a queue. I have implemented the main loop as it (in Java) as

	while (cells.size() > 0) {
		// Next cell to process
		MarchCell next = cells.remove(0);

		// How many triangles do we need for this cell
		int nTriangles = MARCHER.marchCube(next, newTriangles, ISOLEVEL);
		if (nTriangles > 0) {
			addTriangles(nTriangles, newTriangles);
			// Add the triangles from this cell and add neighbors

Then your marchNext method only need to know how to add the neighbors of the the current cube and add them to the queue.

This can also easily be translated into a multithreaded algorithm.

Some thoughts:

Make sure you separate out your data generation/storage from your Unity mesh generation and gameobject creation. I’m assuming you are storing your data in a 128x128x128 array. When you create the actual internal data values, run that over and over and see if that is causing an increasing memory usage. This will tell you if your data generation has problems. Now…I have no idea what your data gen and storage looks like, but if it is just calculating and storing values in the array, seems like that wouldn’t be the most likely suspect for your memory usage going up and up and up.

Unless you have a 128x128x128 array of classes or structures, and you are recreating instances of those for EACH element of the array, each time you recalculate the data, instead of just reusing them. With that much data…I would reuse them, bigtime.

Anyway…let’s say you can just run the part of your code that creates the data, many times for different data, and your memory usage is fine. Then that tells me it’s something in the Unity gameobject/mesh creation.

So I would next isolate the part of your code that generates the actual mesh data (vertices, colors, etc). Rerun the entire process several times (in a loop maybe), and see if your memory problems start up. Don’t actually create the gameobject yet. This is just to make sure that generating the vertex and other data for the mesh is not the problem.

If memory is still behaving…I would think it was a problem with Unity’s way of handling gameobjects. You may have to just reuse them, instead of destroying them and recreating them over and over. I don’t understand much about how unity handles memory…but in my experience…it doesn’t seem to handle it well.

Anyway, hope this ramble is of some use. Heck, it may even be somewhat accurate :slight_smile:

So here is the full thing, lighted as I can.

Memory problem

I want to display different molecular models one after another so it’s something like playing an animation using several frames. At first start I load all the models, which are flattened arrays density maps of 128x128x128. So with my test data (11 density maps) the minimum size I have to load is already 128**3 * 11 * 4 bytes =~ 93 MB.
Each model is 8MB and I’m using ~30 MB of variables when I generate a surface from each file, using my implementation of marching cubes algorithm.
It’s really rare when memory drops a bit, from something like 10% and it’s happening really rarely. It usually grows from several MB at each model generation.

Can somebody tell me how am I censed to have my variables being REUSED EACH TIME I call the method, or to have this class being instantiated a UNIQUE time ?

Stack overflow

When I generate the mesh using recursion, I have a large stack size that sometimes generate stack overflow errors. I tried to force a stack size using Thread overloaded method, but now I can’t generate gameObjects in this Thread, this kind of manipulation has to be done in the main thread. Should I recuperate the data from the thread and generate the mesh in the main thread ? (what I assume I can do if I generate the mesh in my main program script). Or maybe there are easier/nicer ways to do this ?

Main script

using UnityEngine;
using System;
using System.Collections;
using MarchingCubes;

class MainProg : MonoBehaviour {
    private ImportSPIDER ImportSPIDERInstance; // global instantiation
    private MarchingCubesRec MCInstance;
    private int[] NZ; // dimensions of each density grid
    private int[] NY;
    private int[] NX;
    private Vector4[] pointstmp; // whole file values, temporary for one file
    private Vector4[][] points; // whole files values storage
    private string[] filePath = {"frame0_lp10A", "frame4_lp10A", "frame7_lp10A", "frame10_lp10A"};
    private int currentFile;
    // + other variables
    void Start () {

    nbImportedFiles = filePath.Length; // get number of imported files
    ImportSPIDERInstance = new ImportSPIDER(); // initialize SPIDER import instance
    MCInstance = new MarchingCubesRec();

    for (int i=0; i < nbImportedFiles; i++) { // import all of the files determined by user
                    ImportSPIDERInstance.Import(filePath*, out NZtmp, out NYtmp, out NXtmp, out pointstmp); // import SPIDER file*

_ points = new Vector4[pointstmp.Length];_
_ NZ = NZtmp;
NY = NYtmp;
NX = NXtmp;
* for (int j=0; j < pointstmp.Length; j++)
points[j] = pointstmp[j];
void Update () {
CameraState(); // no problem from here
void OnGUI () {
// on user demand using currentFile*

void GenerateNewSurface() { // generate new isosurface using current GUI settings
DestroySurface (); // destroy previous one using Destroy();
MCInstance.MCRecMain(NX[(int)currentFile-1], NY[(int)currentFile-1], NZ[(int)currentFile-1], points[(int)currentFile-1]);
Files Import
using UnityEngine;
using System;
using System.IO;_

class ImportSPIDER {

* public void Import (string filePath, out int NZ, out int NY, out int NX, out Vector4[] points) {*
TextAsset file = Resources.Load(filePath) as TextAsset;
Stream stream = new MemoryStream(file.bytes);
* BinaryReader br = new BinaryReader(stream);*
* int streamLength = (int)br.BaseStream.Length;*
* byte[] bytes = new byte[streamLength];*
* stream.Close ();*
// then use the array “bytes” to have my data
Marching Cubes
using UnityEngine;
using System.Collections.Generic;
using System;

public class MarchingCubesRec {

private GenerateMesh GMInstance;
private int nbIndTriangles; // size of mesh.triangles
private int nbIndVertices; // size of mesh.vertices
private bool[] marchedCubes; // list of length “dataLength”, indicates if cubes already have been marched
private int[] vertIndexGrid; // list of length “dataLength”, records indexes of previously created vertices, so we can build the triangle indexes list using unique vertices
private int nbMarchedCubes; // nb of cubes that have been marched
private int dataLength; // total nb of points, = ncellsX * ncellsY * ncellsZ
private int[] indList; // stores all grid points indices (“ind”) which are >= density threshold (“minValue”)
private int indFound;
// + other variables as private

public void MCRecMain(int NX, int NY, int NZ, float minV, Vector4[] P, float tolV) {
* ncellsX = NX;*
* ncellsY = NY;*
* ncellsZ = NZ;*
* toleranceValue = tolV;*
* minValue = minV;*
* GMInstance = new GenerateMesh();*
* depthSize = ncellsY;*
_ sliceSize = (ncellsX) * depthSize;
dataLength = ncellsX * ncellsY * ncellsZ;
marchedCubes = new bool[dataLength]; // initialize to false, no cubes have been marched
// + other variables declaration, using mainly “new”_

MCFindEachIndex (); // find all points inside the surface, > density threshold

* for (int i=0; i < indFound; i++) // proceed recursive marching cubes on yet unproceeded cubes*
_ if (!marchedCubes[indList*])
MCRec(indList); // lots of calculation without any variable declaration/instantiation or whatever*_

* Mtriangles = new int[nbIndTriangles]; // allocate mesh triangles and vertices, final size*
* Mvertices = new Vector3[nbIndVertices];*

* for (int i=0; i < nbIndTriangles; i++)*
Mtriangles = TMPtriangles*;*
* for (int i=0; i < nbIndVertices; i++)*
Mvertices = TMPvertices*;*

* GMInstance.GM(Mvertices, Mtriangles, center); // generate display, eventually split on several objects < 65k vertices (Unity limit)*
Mesh Generation
using UnityEngine;
using System.Collections.Generic;
using System;

public class GenerateMesh {

* GameObject GOSurface;*
* Mesh mesh;*

* public void GM (Vector3[] Mvertices, int[] Mtriangles, Vector3 center) {*

* GOSurface = new GameObject(“MC Surface”);*
* GOSurface.tag = “surfaceOBJ”;*
* mesh = new Mesh();*

* GOSurface.AddComponent();*
* GOSurface.AddComponent();*
* GOSurface.GetComponent().mesh = mesh;*
* GOSurface.renderer.material = new Material(Shader.Find(“Diffuse”));*
* GOSurface.transform.localPosition = center;*
* mesh.Clear();*

* mesh.vertices = Mvertices;*
* mesh.triangles = Mtriangles;*
* mesh.RecalculateNormals();*
* }*

Hello :slight_smile: Thanks, that was exactly what I was searching for !

Using queues allowed me to pass over my stack overflow problem (and that’s really nice :D).
Since you seem to have gone through the same problems I’m facing right now, I would have just a few more specific questions.

How can you succeed to multithread this algorithm since you need to recuperate vertices positions (if you want to have unique vertices) ?

If you have to draw different surfaces, I mean different parts really separated one from another, but present one the same file, how would it be possible to proceed ?