内存压力在MonoTouch中加载一堆PNG图像

时间:2012-04-23 07:20:32

标签: ios memory-management xamarin.ios uiimage profiling

我有一个MonoTouch应用程序,每1/12秒加载一个帧。我正在使用UIkit,而不是opengl。我在视图中有一个UIImage,并且有一个backgroundtask我正在加载图像。

一切都还可以,但是,一分钟后(或多或少),应用程序停止,跟踪器给我“低内存压力”

它在模拟器中工作正常,没有任何问题。我正在查看分析器,似乎内存已经处理好,但是当我在iPad上试用它时:....(

我使用image.Dispose()释放内存。我在内存中有2个图像,显示其中一个然后释放旧图像。这种行为没问题,因为我在Windows Phone上具有相同的逻辑,并且工作正常。

我已经尝试不使用backgroundTask,并直接从主线程加载图像。它给了我更多时间!如果我使用backgroundTask,应用程序运行30秒然后退出。如果我不使用backgroundTask,它会持续1分钟。

我不知道该怎么办!!!!有人可以帮帮我吗?

感谢!!!

Texture2D.FromStream它只是UIImage.FromFile的包装器

这是后台工作人员:

  void LoadTextureInBackground()
    {
        if (currentMovie == null) return;

        DateTime timeOnstart = DateTime.Now;

        // Mantenemos 2 texturas en memoria para no cargar sobre el mismo objeto texture.
        string fileName = currentMovie.GetFileName();

        if (lastFileName == fileName) return;

        textureLoaded[currentTexture] = Texture2D.FromStream(Device.GraphicsDevice, fileName);

        texture = textureLoaded[currentTexture];

        currentTexture = 1 - currentTexture;

        lastFileName = fileName;

        GC.Collect();
        System.Threading.Thread.Sleep(50);
    }

这是绘制方法:

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    public void Draw(TimeSpan totalTime,TimeSpan elapsedTime)
    {
        if(currentMovie==null) return;

       // Mantenemos 2 texturas en memoria para no cargar sobre el mismo objeto texture.

        if (texture == null) return;

        int newWidth = (int)(texture.Width*RenderSize);
        int newHeight = (int)(texture.Height*RenderSize);

        Texture2D drawTexture = texture;

        // Al cargar usando Texture2D.FromStream, la textura NO lleva elAlpha premultiplicado

        //Device.SpriteBatch.Draw(drawTexture, destination, Color.White);
        if(CultTravel.AppDelegate.ImagePng.Image!=drawTexture.Texture)
        {
            AppDelegate.ImagePng.Image=drawTexture.Texture;
            AppDelegate.ImagePng.Frame=new System.Drawing.RectangleF(0,480-newHeight,ImagePng.Image.CGImage.Width,newHeight);

        // Si la textura que tengo cargada y lista para mostrar es diferente a la que mostraba, libero la antigua
        if (lastTextureDraw!=null && lastTextureDraw != texture)
        {
            lastTextureDraw.Dispose();
        }

        lastTextureDraw = texture;

    }

注意: 我刚刚解决了这个问题,但是我必须禁用后台工作程序,在Draw方法中添加加载代码并在主线程中添加GC.Collect:

       if (lastTextureDraw!=null && lastTextureDraw != texture)
        {
            lastTextureDraw.Dispose();
            // I MUST ADD THIS TO WORK AND DISABLE THE BACKGROUND TASK!!
            GC.Collect();
        }

2 个答案:

答案 0 :(得分:1)

我刚刚解决了这个问题,但我必须禁用后台工作程序,在Draw方法中添加加载代码并在主线程中添加GC.Collect:

   if (lastTextureDraw!=null && lastTextureDraw != texture)
    {
        lastTextureDraw.Dispose();
        // I MUST ADD THIS TO WORK AND DISABLE THE BACKGROUND TASK!!
        GC.Collect();
    }

所以,使用线程时出了点问题......

答案 1 :(得分:0)

  

它在模拟器中工作正常,没有任何问题。

这不是模拟器,而是模拟器。因此,它不会尝试模仿特定设备,包括它的内存限制。 IOW iOS模拟器可以访问更多内存而不是iPad(第一代256MB,第二代512MB,第三代1GB)。

  

我正在查看分析器

哪一个? MonoDevelop的HeapShot还是Apple的乐器?

  

我使用image.Dipose()来释放内存。

这是一个好主意 - 但 只能在管理方面工作。例如。一些API将缓存图像,因为它不是托管内存(它本地分配的内存),因此内存不会显示在HeapShot上。您将有更好的机会使用Apple的仪器跟踪此事。

它可能也是其他东西......就像@ Jonathan.Peppers问的那样,看到你如何加载图像可以帮助我们看出错误。