0

My game has a baseline memory usage of around 315 MB. However calling the following functions leads to a sharp rise in memory usage, leveling out at around 480 MB while reaching spikes of 580 MB and more, accompanied by memory warnings and even crashes.

What happens: First the TakeScreenshot IEnum is called three times in a row, wich is the max. count for screenshots in one session. Second the function SendEmailTask is called showing all three pictures for the user to choose one. By choosing picture "#1" the function SendImage1 is triggered.

Maybe someone can point me to where and how I can get some of that memory back, that would be really great!

All relevant code should be here:

public class Picture : MonoBehaviour {

    private int ssCount = 0;

    private Sprite cachedImage1sprite;
    private Sprite cachedImage2sprite;
    private Sprite cachedImage3sprite;

    private Texture2D cachedImage1;
    private Texture2D cachedImage2;
    private Texture2D cachedImage3;

    private Texture2D JPGtex1;
    private Texture2D JPGtex2;
    private Texture2D JPGtex3;

    private Texture2D tex;


    void Awake () {


    }

    // Use this for initialization
    void Start () {

        JPGtex1 = new Texture2D (2, 2, TextureFormat.RGB24, false );
        JPGtex2 = new Texture2D (2, 2, TextureFormat.RGB24, false );
        JPGtex3 = new Texture2D (2, 2, TextureFormat.RGB24, false );

        // Create a texture the size of the screen, RGB24 format
        int width = Screen.width;
        int height = Screen.height;
        tex = new Texture2D( width, height, TextureFormat.RGB24, false );


    }

    // Update is called once per frame
    void Update () {

        if (ssCount == 0) {

            SendEmail.interactable = false;
            TakePhoto.interactable = true;

        } else if (ssCount == 1) {

            SendEmail.interactable = true;

        } else if (ssCount == 3) {

            TakePhoto.interactable = false;

        }

        //Debug.Log (ssCount);

    }


    void SendEmailTask(){

        if (ssCount == 3) {

            cachedImage1 = SA.IOSNative.Storage.AppCache.GetTexture ("IMAGE_1");

            cachedImage2 = SA.IOSNative.Storage.AppCache.GetTexture ("IMAGE_2");

            cachedImage3 = SA.IOSNative.Storage.AppCache.GetTexture ("IMAGE_3");

            ImagePicker.SetActive (true);

            //Image1
            Rect rec1 = new Rect(0, 0, cachedImage1.width, cachedImage1.height);
            cachedImage1sprite = Sprite.Create(cachedImage1, rec1, new Vector2(0,0),1);
            Image1.image.sprite = cachedImage1sprite;

            //Image2
            Rect rec2 = new Rect(0, 0, cachedImage2.width, cachedImage2.height);
            cachedImage2sprite = Sprite.Create(cachedImage2, rec2, new Vector2(0,0),1);
            Image2.image.sprite = cachedImage2sprite;

            //Image3
            Rect rec3 = new Rect(0, 0, cachedImage3.width, cachedImage3.height);
            cachedImage3sprite = Sprite.Create(cachedImage3, rec3, new Vector2(0,0),1);
            Image3.image.sprite = cachedImage3sprite;

            SA.IOSNative.Storage.AppCache.Remove ("IMAGE_1");
            SA.IOSNative.Storage.AppCache.Remove ("IMAGE_2");
            SA.IOSNative.Storage.AppCache.Remove ("IMAGE_3");

        }

    }

    IEnumerator TakeScreenshot() {

        // Wait till the last possible moment before screen rendering to hide the UI
        yield return null;
        GameObject.Find("Buttons").GetComponent<Canvas>().enabled = false;
        FlashImage();

        // Wait for screen rendering to complete
        yield return new WaitForEndOfFrame();

        // Create a texture the size of the screen, RGB24 format
        int width = Screen.width;
        int height = Screen.height;

        // Read screen contents into the texture
        tex.ReadPixels( new Rect(0, 0, width, height), 0, 0 );
        tex.Apply();

        //byte[] screenshot = tex.EncodeToPNG();

        print("Size is " + tex.width + " by " + tex.height);

        if (ssCount == 0) {

            SA.IOSNative.Storage.AppCache.Save ("IMAGE_1", tex);

            ssCount++;

        } else if (ssCount == 1) {

            SA.IOSNative.Storage.AppCache.Save ("IMAGE_2", tex);

            ssCount++;

        } else if (ssCount == 2)  {

            SA.IOSNative.Storage.AppCache.Save ("IMAGE_3", tex);

            ssCount++;

        }

        IOSCamera.Instance.SaveTextureToCameraRoll(tex); //Save to Cameraroll

        // Show UI after we're done
        GameObject.Find("Buttons").GetComponent<Canvas>().enabled = true;

    }


    public void SendImage1() {

        byte[] screenshot1;

        screenshot1 = cachedImage1.EncodeToJPG ();

        if (Facebook == false) {

            JPGtex1.LoadImage (screenshot1);

            TextureScale.Bilinear (JPGtex1, 1200, 900);

            IOSSocialManager.Instance.SendMail (SubjectText, EmailText, "", JPGtex1);

        } else {

            StartCoroutine(UploadToPage(screenshot1));

        }

        backToGame ();

    }

    public void backToGame() {

        Destroy (cachedImage1sprite);
        Destroy (cachedImage2sprite);
        Destroy (cachedImage3sprite);

        SA.IOSNative.Storage.AppCache.Remove ("IMAGE_1");
        SA.IOSNative.Storage.AppCache.Remove ("IMAGE_2");
        SA.IOSNative.Storage.AppCache.Remove ("IMAGE_3");

        Destroy(cachedImage1);
        Destroy(cachedImage2);
        Destroy(cachedImage3);

        cachedImage1 = null;
        cachedImage2 = null;
        cachedImage3 = null;

        Image3Obj.SetActive (true);

        ImagePicker.SetActive (false);

    }

}   

EDIT

Detailed memory profiler after going thru the routine twice:

Detailed memory profiler after going thru the routine twice

Xcode memory profiler after going thru the routine twice:

Xcode memory profiler after going thru the routine twice

somejonus
  • 67
  • 1
  • 11
  • Have you run your application with the profiler running? This will allow you to see exactly what's using so much memory. – Eoghan May 10 '17 at 15:14
  • Can you upload a screenshot of the detailed memory profiler after using your app for a while? You must destroy every single unused texture or it will remain in memory. – Juan Bayona Beriso May 10 '17 at 15:25
  • @JuanBayonaBeriso edited my question with screenshots. – somejonus May 10 '17 at 17:50
  • @Eoghan The profiler is not really telling me a lot. Especially if you take into account that it says im using almost 100 MB less than what Xcode is showing. Also im not to sure what 83.5 MB "Objects" is supposed to mean. – somejonus May 10 '17 at 17:57

2 Answers2

0

From your profiler report;

You're using a big chunk of memory on Meshes and Texture2D Assets - that'd suggest to me you're possibly drawing over them/hiding them from the user rather than actually removing them from memory. 50+ MB in Texture2D Assets is a little odd considering you've got a further 120+ MB of Meshes being loaded in. I'm assuming from that that it's a 3D game, but has a 2D UI? If so, then 50MB is quite a lot to be spending on Texture2D Assets.

"Objects" are what you think they are - they're Objects. Instantiated classes, or GameObjects containing attached components. So if you made a Player GameObject, and attached to that is a "playerStats" object with a couple of variables for health, speed, stamina etc etc, then that'd count as 2 objects.

80MB isn't too worrying for Objects. Your Texture2D and Meshes use is what would strike me as being pretty high for a game that's targeting iOS. Make sure you're using mobile-friendly models, and textures that aren't too high in resolution.

Eoghan
  • 1,590
  • 2
  • 13
  • 31
  • Thanks for your answer! Reconsidering my meshes and textures got me back a cool 60 MB. But the memory is still adding up to much. What I found out is the following: When `SendEmailTask` is called, the memory usage in the profiler rises by 150 MB of wich 54 MB is Objects and 96 MB is Texture2Ds (the three images - 32 MB each) in "Not Saved". However when `SendImage1` is called and all is destroyed the profiler only shows a 7 MB hike from 295 to 302 MB for the whole app. Xcode on the other side went from 247 MB to 372 MB, wich is the new baseline now. – somejonus May 12 '17 at 12:43
  • Yeah, then thats probably it? can you reuse the memory of your textures instead of creating new ones? I don't know how are you loading them as you are using a plugin of stan assets. – Juan Bayona Beriso May 12 '17 at 13:33
0

I had a similar problem with audio files in iOS, I don't know if this could be your case.

I loaded big audio files of 20mb+ on memory to process them and then release the memory, the thing is that the memory kept going up in the xcode profiler. This is caused by memory fragmentation, you can read more about it here: https://stackoverflow.com/a/3770593/4024219

My solution was to load the files in little chunks and reuse my arrays instead of creating and destroying new ones.

Community
  • 1
  • 1
  • Thank you for your answer! Could you take a look at my comment on the answer below? It looks like fragmentation could be my problem too, since im loading those three 32 MB Texture2Ds. What do you think? – somejonus May 12 '17 at 12:48