【问题标题】:Unity iOS memory usage rises and wont go down againUnity iOS 内存使用量上升且不会再次下降
【发布时间】:2017-10-09 05:59:35
【问题描述】:

我的游戏的基准内存使用量约为 315 MB。然而,调用以下函数会导致内存使用量急剧上升,稳定在 480 MB 左右,同时达到 580 MB 甚至更多的峰值,并伴随着内存警告甚至崩溃。

会发生什么:首先TakeScreenshot IEnum 连续调用 3 次,这是最大值。计算一个会话中的屏幕截图。其次,调用函数SendEmailTask 显示所有三张图片供用户选择一张。通过选择图片“#1”触发SendImage1函数。

也许有人可以指出我可以在哪里以及如何找回一些记忆,那真是太棒了!

所有相关代码都应该在这里:

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);

    }

}   

编辑

经过两次例程后的详细内存分析器:

通过例程两次后的 Xcode 内存分析器:

【问题讨论】:

  • 您是否在运行探查器的情况下运行您的应用程序?这将使您能够准确地看到什么在使用这么多的内存。
  • 您可以在使用您的应用一段时间后上传详细的内存分析器的屏幕截图吗?您必须销毁每一个未使用的纹理,否则它将保留在内存中。
  • @JuanBayonaBeriso 用截图编辑了我的问题。
  • @Eoghan 分析器并没有真正告诉我很多。特别是如果你考虑到它说我使用的空间比 Xcode 显示的少近 100 MB。我也不确定 83.5 MB“对象”应该是什么意思。

标签: c# ios unity3d memory texture2d


【解决方案1】:

来自您的分析报告;

您在 Meshes 和 Texture2D Assets 上使用了大量内存 - 这表明您可能正在绘制它们/向用户隐藏它们,而不是实际从内存中删除它们。考虑到您已经加载了另外 120+ MB 的网格体,Texture2D 资产中 50+ MB 有点奇怪。我假设这是一个 3D 游戏,但有一个 2D 用户界面?如果是这样,那么在 Texture2D 资产上花费 50MB 是相当大的。

“对象”就是你认为的那样——它们就是对象。实例化的类,或包含附加组件的游戏对象。因此,如果您制作了一个 Player GameObject,并附加了一个“playerStats”对象,其中包含健康、速度、耐力等几个变量,那么这将被视为 2 个对象。

80MB 对于对象来说并不太令人担忧。您使用的 Texture2D 和 Meshes 让我觉得对于针对 iOS 的游戏来说相当高。确保您使用的是适合移动设备的模型,以及分辨率不太高的纹理。

【讨论】:

  • 感谢您的回答!重新考虑我的网格和纹理让我得到了一个很酷的 60 MB。但是内存仍然加起来很多。我发现如下:当调用SendEmailTask 时,分析器中的内存使用量增加了 150 MB,其中 54 MB 是对象,96 MB 是“未保存”中的 Texture2Ds(三个图像 - 每个 32 MB) .但是,当调用 SendImage1 并且所有内容都被销毁时,分析器仅显示整个应用程序从 295 到 302 MB 增加了 7 MB。另一方面,Xcode 从 247 MB​​ 变为 372 MB,这是现在的新基线。
  • 是的,大概就是这样吧?你能重复使用纹理的内存而不是创建新的纹理吗?我不知道您在使用 stan 资产插件时如何加载它们。
【解决方案2】:

我在 iOS 中遇到了类似的音频文件问题,我不知道这是否是您的情况。

我在内存上加载了 20mb+ 的大音频文件来处理它们,然后释放内存,问题是内存在 xcode 分析器中不断上升。这是由内存碎片引起的,您可以在此处阅读更多信息:https://stackoverflow.com/a/3770593/4024219

我的解决方案是分小块加载文件并重复使用我的数组,而不是创建和销毁新数组。

【讨论】:

  • 感谢您的回答!你能看看我对下面答案的评论吗?看起来碎片也可能是我的问题,因为我正在加载这三个 32 MB Texture2D。你怎么看?
猜你喜欢
  • 2014-01-26
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多