Huge memory leak!

I’m getting a huge memory leak in my game that I’ve tracked down to some variables that I’m assigning through the inspector:

var dirtTex : Texture2D;
var grassTex : Texture2D;
var rockyGrassTex : Texture2D;
var mountainTex : Texture2D;
var snowTex : Texture2D;

function Start()
{
    ...
}

Each of these textures is 1024 x 1024. Prior to adding these textures to my game, there were no memory problems. Now, every time I run the game in Unity, Unity itself increases its memory footprint by about 300-400 megs of RAM and doesn’t give them up until I quit!

Is it the fact that the variables are global to the script that’s the problem? Should I assign them within the function that needs them? If so, how do I do this? Do I need to instantiate the images as textures or something? Help!

I tried to to DestroyImmediate(grassTex) but it tells me that that will destroy the grassTex asset itself! All I really want to do is take an image and make that into an array of its colors without breaking the bank memory-wise. Does anybody have any ideas for this? My current approach of assigning the textures in the inspector using exposed public variables is just killing my game.

That’s very unlikely. It’s what you’re doing with them that’s probably causing the problem, but without code it’s impossible to say.

You don’t want to destroy assets, but rather instances of them. Also you should probably be using Destroy rather than DestroyImmediate unless you have a good reason otherwise.

–Eric

What are you doing with these textures in your script? Are you taking their public reference, then copying them (array?).

Show some more code than just the assignment, because that’s not what is causing the problem. Show us what you do with those public variables in your code.

Here’s the code. All I’m doing is reading each of them into an array of colors.

// 1024 x 1024 image assets are assigned to these variables in the inspector
var dirtTex : Texture2D;
var grassTex : Texture2D;
var rockyGrassTex : Texture2D;
var mountainTex : Texture2D;
var snowTex : Texture2D;

function Start()
{
    createTexture(heightMapArray)
    // heightmapArray is created in other functions
    // that I am 100% sure are not causing the problem
}


function createTexture(heightmapArray)
{
    var dirtTexArray = dirtTex.GetPixels(0);
    var grassTexArray = grassTex.GetPixels(0);
    var rockyGrassTexArray = rockyGrassTex.GetPixels(0);
    var mountainTexArray = mountainTex.GetPixels(0);
    var snowTexArray = snowTex.GetPixels(0);

    var tempTextureArray = new Color[textureResolution * textureResolution];
    var texture = new Texture2D(textureResolution, textureResolution);

    for (var i = 0; i < heightmapArray.Length; i++)
    {
        // for debugging purposes, I just assign currentColor to blue
        // instead of doing any processing
        currentColor = Color.blue;
        tempTextureArray[i] = currentColor;
    }
    texture.SetPixels(tempTextureArray, 0);
    texture.Apply();
    renderer.material.mainTexture = texture;
    
    bytes = texture.EncodeToPNG();
    File.WriteAllBytes(Application.dataPath + "/../texture.png", bytes);
}

Doing some more debugging, it looks like the culprit is when I read the textures into arrays. Is there a more efficient way to do this, and/or can I easily toss the arrays when I’m finished with them?

most important: clean them again
but I would ask myself why you read them in if you don’t use them at all.
Don’t use and access what you don’t need, that only wastes RAM and time.

Also, never write “100% sure” in a comment unless you are and can be 100% sure. It doesn’t make anyone trust any answer you give as the code pretty clearly shows the 100% are more than just slightly off reality. You don’t seem to have even basic knowledge of how managed environments work at all.

There is pertty sure no, the memory is free actually. Its just allocated by your program as the GC won’t return memory to the OS so any memory watching outside of the application will plain simply fail.

It’s true I don’t have a very good grasp of this kind of stuff, but that’s why I’m here asking for help! :slight_smile:

It must have looked like I wasn’t using those variables at all, but I just didn’t include the code that referenced them because that code isn’t working yet. :sweat_smile: But the long and short of it is that I use these arrays of colors to generate a texture by blending together the colors and putting it in a new array, then assigning that array to a texture and applying the texture. If there’s a more efficient way of doing this, I’d be overjoyed to hear what it is!

This is all the code for what I’m doing with the arrays of colors (this code doesn’t work yet, but hopefully it should indicate what I’m trying to do):

function CreateTexture(heightmapArray)
{
    var dirtTexArray = dirtTex.GetPixels(0);
    var grassTexArray = grassTex.GetPixels(0);
    var rockyGrassTexArray = rockyGrassTex.GetPixels(0);
    var mountainTexArray = mountainTex.GetPixels(0);
    var snowTexArray = snowTex.GetPixels(0);
    
    var tempTextureArray = new Color[textureResolution * textureResolution];
    var currentColor = Color.black;
    var heightmapValue = 0.0;
    var range = (1.0 / 5);
    var currentMod = 0.0;
    
    var texture = new Texture2D(textureResolution, textureResolution);
    
    for (var i = 0; i < heightmapArray.Length; i++)
    {
        // grab the red component of this pixel as a height value
        heightmapValue = heightmapArray[i].r;
        
        currentMod = 0.0;
        
        // don't go through this song-and-dance for water
        if (heightmapValue == 0.00)
        {
            currentColor = Color.blue;
        }
        else
        {
            // dirt
            currentMod = (range - Mathf.Abs(heightmapValue - 0.05)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (dirtTexArray[i] * currentMod);
            }

            // grass
            currentMod = (range - Mathf.Abs(heightmapValue - 0.25)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (grassTexArray[i] * currentMod);
            }
            
            // more grass
            currentMod = (range - Mathf.Abs(heightmapValue - 0.50)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (grassTexArray[i] * currentMod);
            }
            
            //rocky grass
            currentMod = (range - Mathf.Abs(heightmapValue - 0.70)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (rockyGrassTexArray[i] * currentMod);
            }
            
            // mountain
            currentMod = (range - Mathf.Abs(heightmapValue - 0.95)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (mountainTexArray[i] * currentMod);
            }
            
            // snow
            currentMod = (range - Mathf.Abs(heightmapValue - 1.1)) / range;
            if (currentMod > 0)
            {
                currentColor = currentColor + (snowTexArray[i] * currentMod);
            }
        }
       
        // assign the aggregated color
        tempTextureArray[i] = currentColor;
    }
    
    texture.SetPixels(tempTextureArray, 0);
    texture.Apply();
    renderer.material.mainTexture = texture;
    
    bytes = texture.EncodeToPNG();
    File.WriteAllBytes(Application.dataPath + "/../texture.png", bytes);
}

still, it doesn’t leak any memory.
As mentioned, the GC will keep the memory reserved from the OS, thats what you see from the outside.

But not all memory thats reserved is in use. There is likely pooled memory, thats were new objects are allocated into and through the pooling this is possible very efficientely.

If it would allocate and deallocate the memory all the time it would run at a crawl, especially incases like yours where you create and trash data of such size within the glimpse of an eye.

Only the System.GC class knows how much memory is currently used and how much is free for pooling.
MSDN contains more information about the C# System.GC class

Thanks for the explanation, that makes sense. It seems like my approach isn’t very well-suited for Unity’s environment. Based on the code I’ve posted, can you think of a better way to accomplish what I’m trying to do?

The reason I want to load images into arrays is because I can manipulate the array data very efficiently versus (shudder)iterating through the texture and calling getPixel() on each one… but the memory hit incurred by creating those arrays from images is very troublesome. Is there a less memory-intensive way to do this? I mean, there have to be relatively painless ways of programmatically reading and altering textures, right?

Thats the best approach likely.
You can’t store global arrays or alike as you don’t have fixed texture sizes.

And GetPixels / SetPixels etc is the painless way of reading and altering textures. Textures are no cpu thing but a GPU thing, as such accessing them always includes a copy to memory.

also I think you are still confused: Above approach is no problem.
The memory use will raise at first but then become stable and remain on that level

When I play my game in Unity, Unity increases its memory footprint by the established amount. Fine. As per what you’ve said, this is normal, and I understand that. However, when I stop the game and return to working on it in the Unity editor, Unity does not give up the memory that the game used, even though the game is no longer running. Thus, after I test my game in Unity a few times, Unity had gobbled up more than a gig of RAM and will not give it back. My system becomes very unresponsive. So In order to free the memory, I have to quit Unity every three or four times I test my game. Why wouldn’t Unity give back the memory that a game has allocated for itself once the game is no longer running? This seems gratuitous.

If unity is restoring memory when you log out of unity, the memory problem is probably a programming problem, not a unity problem.

Still, reading a bunch of textures into an array shouldn’t make Unity keep on gobbling up more memory. It might be something else causing this, but I’d like our QA to look into this.

Please file a bug with your project and precise steps to reproduce - then we’ll take a look and see what we can do about it.

I’m experiencing the same issue sladuuch is pointing at, Unity will not free the memory used by the game when executed inside the editor, as a result my system will eventually run out of memory and I’ll be forced to relaunch Unity.

Is this how its supposed to work?? is it a bug??

I posted a simple script that clearly shows what I’m doing

http://forum.unity3d.com/viewtopic.php?p=192455#192455

nicholas, I have filed a bug using Unity’s built-in issue reporter tool (Case 281564)