Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegate Closure with no memory allocation

I wrote a Thread helper class that can be used to execute a piece of code in Unity's main Thread.

This is the functions blue print:

public static void executeInUpdate(System.Action action)

The complete script is really long and will make this post unnecessarily long. You can see the rest of the script helper class here.

Then I can use unity's API from another Thread like this:

UnityThread.executeInUpdate(() =>
{
    transform.Rotate(new Vector3(0f, 90f, 0f));
});

The problem is that when I use a variable declared outside of that delegate, it would allocate memory. The code above allocates 104 bytes each frame. That's because of the transform variable that is used inside that closure.

This may seem like nothing now but I do this 60 times per-sec and I have about 6 camera's I need to connect to and display images on the screen. I do not like the amount of garbage that is generated.

Below is an example of how I am downloading images from a camera and uploading it into Unity. I get about 60 frames per-sec. The receiveVideoFrame() function runs on a separate Thread. It downloads the image, send's it to Unity's main Thread and Unity uploads the image bytes into Texture2D. The Texture2D is then displayed with RawImage. The allocation happens when closure is captured due to UnityThread.executeInUpdate.

bool doneUploading = false;
byte[] videoBytes = new byte[25000];
public Texture2D videoDisplay;

void receiveVideoFrame()
{
    while (true)
    {
        //Download Video Frame 
        downloadVideoFrameFromNetwork(videoBytes);

        //Display Video Frame 
        UnityThread.executeInUpdate(() =>
        {
            //Upload the videobytes to Texture to display
            videoDisplay.LoadImage(videoBytes);
            doneUploading = true;
        });

        //Wait until video is done uploading to Texture/Displayed
        while (!doneUploading)
        {
            Thread.Sleep(1);
        }

        //Done uploading Texture. Now set to false for the next run
        doneUploading = false;

        //Repeat again
    }
}

How can I use closure without causing memory allocation?

If that's not possible, is there another way to do this?

I can just remove the class I use to execute code in the main Thread and re-write those logic in the main script but that would be messy and long.

like image 769
Programmer Avatar asked Nov 07 '22 22:11

Programmer


1 Answers

After hours of experiment I discovered that if you put the code with the closure in a function, then cache it to an Action variable once in the Start or Awake function, the closure memory allocation will be gone when you invoke it in inside the while loop.

Also, I made the doneUploading boolean variable a volatile so that both Threads can see the changes. I don't think that the lock keyword is needed for this boolean variable here.

private volatile bool doneUploading = false;

byte[] videoBytes = new byte[25000];
public Texture2D videoDisplay;

Action chachedUploader;

void Start()
{
    chachedUploader = uploadToTexture;
}

void uploadToTexture()
{
    UnityThread.executeInUpdate(() =>
    {
        //Upload the videobytes to Texture to display
        videoDisplay.LoadImage(videoBytes);
        doneUploading = true;
    });
}

//running in another Thread
void receiveVideoFrame()
{
    while (true)
    {
        //Download Video Frame 
        downloadVideoFrameFromNetwork(videoBytes);

        //Display Video Frame (Called on main thread)
        UnityThread.executeInUpdate(chachedUploader);

        //Wait until video is done uploading to Texture/Displayed
        while (!doneUploading)
        {
            Thread.Sleep(1);
        }

        //Done uploading Texture. Now set to false for the next run
        doneUploading = false;

        //Repeat again
    }
}

I am open to more improvement if anyone find anything bad. Although, I have solved my problem. Closures does not allocate memory anymore.

like image 197
Programmer Avatar answered Nov 15 '22 12:11

Programmer