2

I have a MonoTouch application that loads a frame every 1/12th of second. I'm using the UIkit, not opengl. I have an UIImage into the view, and with a backgroundtask i'm loading the images.

Everything is ok, but, after a minute (more or less), the application stops, and the tracer gives me a 'low memory pressure'

It works fine in the emulator, with no problems. I'm looking at the profiler and it seems that the memory is disposed, but when i try it on the iPad.... :(

I free the memory using image.Dispose(). I have 2 images in memory, showing one of then and then releasing the older. This behaviour is ok, because i have the same logic on the Windows Phone and it works fine.

I've tried not to use the backgroundTask, and load the image directly from the main Thread. It gives me more time!!! If i use the backgroundTask, the application runs for 30 seconds and then exits . If i NOT use the backgroundTask, it lasts 1 minute.

I don't know what to do!!!! Can anyone help me, please?

Thanks!!!

Texture2D.FromStream it's only a wrapper for UIImage.FromFile

This is the background worker:

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

This is the draw method:

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

    }

Note: I've just solved the issue, BUT i have to disable the background worker, add the loading code in the Draw method and add the GC.Collect in the main thread:

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

2 Answers2

1

I've just solved the issue, BUT i have to disable the background worker, add the loading code in the Draw method and add the GC.Collect in the main thread:

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

So, something is wrong when working with threads....

  • Try using MonoTouch 5.3 **alpha** to build your application. It will, by default for debug builds, add checks to ensure you're not using UIKit outside the main thread (a common mistake that can be hard to find/diagnose). – poupou Apr 25 '12 at 19:45
  • What do you mean by "using UIKit outside the main thread"? Why UIImage.FromFile is not usable from another thread? – Emanuele Sabetta May 02 '12 at 13:03
0

It works fine in the emulator, with no problems.

This is not an emulator but a simulator. As such it does not try to mimic a specific device, including it's memory restrictions. IOW the iOS simulator has access to much more memory than your iPad (1st gen 256MB, 2nd gen 512MB, 3rd gen 1GB).

I'm looking at the profiler

Which one ? MonoDevelop's HeapShot or Apple's Instruments ?

I free the memory using image.Dipose().

That's a good idea - but it could only work on the managed side. E.g. some API will cache images, that memory won't show on HeapShot since it's not managed memory (it's natively allocated memory). You'll have a better chance to track this using Apple's Instruments.

It could be something else too... which means, like @Jonathan.Peppers asked, that seeing how you're loading the images could help us to see what's wrong.

poupou
  • 43,413
  • 6
  • 77
  • 174