There is clearly something wrong. I've tried to plug a leak in
BitmapFactory.decodeStream() (which is called internally by
BitmapFactory.decodeFile() ), and that indeed fixed a memory leak
whenever you create a bitmap (see http://review.source.android.com/6418),
but after Romain reviewed it, I realized that the problem is possibly
much deeper in the gc itself.

BitmapFactory.decodeStream() sometimes creates a BufferedInputStream()
and doesn't close it.... but in theory, that shouldn't cause a memory
leak. The GC should realize that nobody references the
BufferedInputStream(), collect it, and thereby realize that nobody
holds its enclosing stream and collect that too. Except that this
doesn't happen. (Unless I missed something secret that links the
FilteredInputStream to the other stream on a lower level.)

I've made a simple test app that creates a Bitmap using
BitmapFactory.decodeFile() every 10ms. It doesn't even store the
return value, and lo and behold, the app runs out of memory unless I
modify the Android OS to close the BufferedInputStream.

I'll take a peek at the mark and sweep mechanism itself, but it would
be more productive if somebody at Android could do that since they're
a lot more familiar with all this.


Btw, Jose - I too got OOMs when I was nowhere close to 16MB, although
my suspicion is that the JNI memory usage is not easily accessible in
the DDMS (even though somebody said it is supposedly taken from the
app's heap as well).

-Mike


On Dec 31, 5:35 am, qvark <[email protected]> wrote:
> 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
> > > >> >> >> >              
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
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