We have also been noticing this kind of behaviour in our application.

What is worse, many of the OOM problems (but not all) have been solved
using explicits System.gc() calls before the operation that caused the
OOM. IMHO this means we were doing our homework releasing all the
references to unused objects, but Dalvik was not freeing the memory
until we have 'forced' it.

This morning have been the last example: take a picture with the
camera and display it in a new activity, finish that activity and when
you try to capture a new picture you will get an OOM. You could thing
we are doing something wrong and there is some reference to the image
that prevents it from being garbage collected, but then I modify the
activity that takes the pictures and put a System.gc(); before the
takePicture() call and... it works! now you can take a picture,
visualize it, go back and take another picture as many times as you
want.

I have always considered an explicit call to System.gc() a bad
practice because that should be the VM's work not the programmer one,
so I was very puzzled when I tried this and it worked... is this the
intended behaviour in Dalvik? should we populate our code with
System.gc() calls?

BTW, Romain, please believe us when we say there are OOM exceptions
when you are not even close to the theoretical 16 MB limit and you try
to reserve a significant amount of memory (say 1 MB for example).

Thanks,

Jose Luis.

On Dec 30, 6:42 pm, blindfold <[email protected]> wrote:
> I wonder if there could be some bug in this intended VM-like
> behaviour, because my app continuously uses about 3 to 4 MB on the dev
> phone 1 according to DDMS (with similar figures reported by freeMemory
> ()), and DDMS reports a heap size of about 6 MB (not a typo, not 16
> MB). And yet my app occasionally crashes due to an OutOfMemoryError
> exception when its peak usage gets close to that fixed 6 MB (not 16
> MB), either in my own (modest, few hundred KB) memory allocations -
> for which I can add try-catch blocks as a crude workaround to keep the
> app alive, or due an out-of-memory error in the low-level camera
> preview code, which then inevitably causes a crash. Never do I see the
> heap (in DDMS) gradually climb up from 6 MB towards 16 MB. Basically
> it looks like the heap does not always grow even when memory
> allocations require it? Or has the system already reserved 10 MB of
> the 16 MB for things that I am not aware of such that the reported
> heap cannot grow above 6 MB?
>
> Thanks
>
> On Dec 4, 9:36 am, Romain Guy <[email protected]> wrote:
>
> > The heap works pretty much like in a regular VM. As your app needs
> > more memory the heap grows accordingly (but doesn't shrink.) For
> > instance, if you are using 1 MB out of your 2 MB of allocated heap and
> > need to load 2 more MB, the heap will grow to more than 3 MB, and you
> > will use 3 MB out of the heap. But when the heap reaches a total
> > allocated size of 16 MB and your app needs more memory, you get an
> > OutOfMemoryError.
>
> > On Wed, Dec 3, 2008 at 11:30 PM, EboMike <[email protected]> wrote:
>
> > > Thanks, Romain. I'm grabbing them from a server, but you're right, if
> > > anything, I should convert and re-save them in a smaller format before
> > > caching them locally. Well, I just tried to get it running quickly :)
>
> > > One laaast thing - You mentioned that an app has a 16MB heap. How is
> > > that split up? A Runtime.getRuntime().freeMemory() right on startup in
> > > the app above gives me about 800KB or so (although the app is later
> > > able to allocate 1MB to decode an image). I'm not very familiar with
> > > Dalvik's memory management, how is the whole thing set up?
>
> > > -Mike
>
> > > On Dec 3, 11:26 pm, Romain Guy <[email protected]> wrote:
> > >> Well you could start by not loading such huge images in a Gallery.
> > >> Even if the recycler was working correctly it is a LOT of data to read
> > >> and to decode. It's also a lot of wasted memory (and it also slows
> > >> drawing down since the bitmaps are drawn rescaled.) You should use
> > >> BitmapFactory.Options or Bitmap.createScaledBitmap to load your image
> > >> pre-scaled to a much more reasonable size.
>
> > >> On Wed, Dec 3, 2008 at 11:23 PM, EboMike <[email protected]> wrote:
>
> > >> > Thanks a lot for the very quick replies. One last thing: Do you happen
> > >> > to have any remote idea about when the next SDK release is scheduled?
> > >> > My app is currently running out of memory a lot :)
>
> > >> > On Dec 3, 11:13 pm, Romain Guy <[email protected]> wrote:
> > >> >> A memory leak is actually totally expected in that case. Gallery, like
> > >> >> ListView, GridView, etc. uses a recycling heap. Every time a view is
> > >> >> unused, it is moved to the recycler. Unfortunately, if it's never
> > >> >> taken out of the recycler...
>
> > >> >> On Wed, Dec 3, 2008 at 11:07 PM, EboMike <[email protected]> wrote:
>
> > >> >> > Thanks a lot, Romain! Question though - even if the gallery is not
> > >> >> > converting the views, why doesn't it release references to them as 
> > >> >> > you
> > >> >> > move away?
>
> > >> >> > Say, I move from view 0 to view 1, with view 0 being completely off-
> > >> >> > screen, the gallery should remove its reference to view 0 since it 
> > >> >> > is
> > >> >> > no longer needed, and thus allow the gc to free up any memory it
> > >> >> > holds. In fact, when I go back to view 0, I can see that a new view 
> > >> >> > is
> > >> >> > created. So what happened to the old view 0? Even with view 
> > >> >> > conversion
> > >> >> > not working, there shouldn't be memory leaks.
>
> > >> >> > -Mike
>
> > >> >> > On Dec 3, 11:04 pm, Romain Guy <[email protected]> wrote:
> > >> >> >> I just checked and the bug is simply that Gallery does not convert 
> > >> >> >> the
> > >> >> >> views. I'll try to fix it as soon as possible.
>
> > >> >> >> On Wed, Dec 3, 2008 at 10:45 PM, EboMike <[email protected]> wrote:
>
> > >> >> >> > I've already asked this in <a 
> > >> >> >> > href="http://groups.google.com/group/
> > >> >> >> > android-developers/msg/9cdbf47be2505810?hl=en">This thread</a>: 
> > >> >> >> > Here
> > >> >> >> > is a pretty simple Gallery setup. It seems to leak with every 
> > >> >> >> > image
> > >> >> >> > that's loaded (see the original thread for details).
>
> > >> >> >> > I'm tempted to file it as a bug, but I want to mention it here 
> > >> >> >> > first
> > >> >> >> > to make sure I'm not just making a simple mistake in my usage of 
> > >> >> >> > the
> > >> >> >> > Gallery. Also (as mentioned in another thread), convertView is 
> > >> >> >> > always
> > >> >> >> > null -- the Gallery never seems to recycle any views. Why?
>
> > >> >> >> > To make this run, you will need to put a JPG file into the data 
> > >> >> >> > folder
> > >> >> >> > (see code).
>
> > >> >> >> > package ebomike.memorytest;
>
> > >> >> >> > import android.app.Activity;
> > >> >> >> > import android.content.Context;
> > >> >> >> > import android.graphics.Bitmap;
> > >> >> >> > import android.graphics.BitmapFactory;
> > >> >> >> > import android.graphics.drawable.BitmapDrawable;
> > >> >> >> > import android.os.Bundle;
> > >> >> >> > import android.util.Log;
> > >> >> >> > import android.view.View;
> > >> >> >> > import android.view.ViewGroup;
> > >> >> >> > import android.widget.BaseAdapter;
> > >> >> >> > import android.widget.Gallery;
> > >> >> >> > import android.widget.ImageView;
>
> > >> >> >> > public class MemoryTest extends Activity {
>
> > >> >> >> >        Gallery g;
>
> > >> >> >> >    /** Called when the activity is first created. */
> > >> >> >> >   �...@override
> > >> >> >> >    public void onCreate(Bundle savedInstanceState) {
>
> > >> >> >> >                String filePath;
>
> > >> >> >> >                // NOTE: Make this point to a JPEG file.
> > >> >> >> >                filePath = getFilesDir().getPath();
> > >> >> >> >                filePath += "/TEST_IMAGE.jpg";
>
> > >> >> >> >        super.onCreate(savedInstanceState);
> > >> >> >> >        setContentView(R.layout.main);
>
> > >> >> >> >        g = (Gallery) findViewById(R.id.Gallery01);
> > >> >> >> >        g.setAdapter(new FullImageAdapter(this, filePath));
> > >> >> >> >    }
>
> > >> >> >> >    class FullImageAdapter extends BaseAdapter
> > >> >> >> >    {
> > >> >> >> >        Context context;
> > >> >> >> >        String path;
>
> > >> >> >> >        FullImageAdapter(Context c, String path)
> > >> >> >> >        {
> > >> >> >> >                context = c;
> > >> >> >> >                this.path = path;
> > >> >> >> >        }
>
> > >> >> >> >        public int getCount()
> > >> >> >> >        {
> > >> >> >> >                return 1024;
> > >> >> >> >        }
>
> > >> >> >> >        public int getViewTypeCount()
> > >> >> >> >        {
> > >> >> >> >                return 1;
> > >> >> >> >        }
>
> > >> >> >> >        public boolean hasStableIds()
> > >> >> >> >        {
> > >> >> >> >                return true;
> > >> >> >> >        }
>
> > >> >> >> >        public int getItemViewType(int position)
> > >> >> >> >        {
> > >> >> >> >                return 0;
> > >> >> >> >        }
>
> > >> >> >> >        public View getView(int position, View convertView, 
> > >> >> >> > ViewGroup
> > >> >> >> > parent)
> > >> >> >> >        {
> > >> >> >> >                ImageView view;
>
> > >> >> >> >                if (convertView != null)
> > >> >> >> >                {
> > >> >> >> >                        // Note that we never get here. Why?
> > >> >> >> >                        view = (ImageView) convertView;
> > >> >> >> >                }
> > >> >> >> >                else
> > >> >> >> >                {
> > >> >> >> >                        view = new ImageView(context);
> > >> >> >> >                }
>
> > >> >> >> >                Bitmap bitmap = BitmapFactory.decodeFile(path);
> > >> >> >> >                BitmapDrawable drawable = new 
> > >> >> >> > BitmapDrawable(bitmap);
> > >> >> >> >                view.setImageDrawable(drawable);
>
> > >> >> >> >                return view;
> > >> >> >> >        }
>
> > >> >> >> >        public Object getItem(int position)
> > >> >> >> >        {
> > >> >> >> >                return position;
> > >> >> >> >        }
>
> > >> >> >> >        public long getItemId(int position)
> > >> >> >> >        {
> > >> >> >> >                return position;
> > >> >> >> >        }
> > >> >> >> >    }
> > >> >> >> > }
>
> > >> >> >> > The layout:
>
> > >> >> >> > <?xml version="1.0" encoding="utf-8"?>
> > >> >> >> > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/
> > >> >> >> > android"
> > >> >> >> >    android:orientation="vertical"
> > >> >> >> >    android:layout_width="fill_parent"
> > >> >> >> > android:layout_height="fill_parent">
> > >> >> >> > <TextView
> > >> >> >> >    android:layout_width="fill_parent"
> > >> >> >> >    android:layout_height="wrap_content"
> > >> >> >> >    android:text="@string/hello"
> > >> >> >> >    />
> > >> >> >> > <Gallery android:id="@+id/Gallery01"
> > >> >> >> > android:layout_width="fill_parent"
> > >> >> >> > android:layout_height="fill_parent"></Gallery>
>
> > >> >> >> > </LinearLayout>
>
> > >> >> >> --
> > >> >> >> Romain Guywww.curious-creature.org
>
> > >> >> --
> > >> >> Romain Guywww.curious-creature.org
>
> > >> --
> > >> Romain Guywww.curious-creature.org
>
> > --
> > Romain Guywww.curious-creature.org
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to