• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Memory Leak issue

j_p36

Newbie
I am having a memory leak and the solutions I've found when searching the web haven't been much help. I know what the problem is, I just don't know how to fix it. The problem is that I'm allocating images as final (actually stored in a final linearlayout view) and they don't get deallocated. But I'm not sure how to do that because of the way I'm creating them.

The problem happens on a screen rotation, when the activity is destroyed and recreated.

Any suggestions are welcome and thanks for your time. My code and error log are below.

Code:
db.open();
        Cursor cursor1 = db.getItemFromInfo("picvid", iid);
        if(cursor1.moveToFirst())
        {
            while(!cursor1.isAfterLast())
            {
                String uriString = cursor1.getString(2);
                final Uri uri2 = Uri.parse(uriString);
                String[] projection = { MediaStore.Images.ImageColumns.DATA, /*col1*/
                                MediaStore.Images.ImageColumns.DISPLAY_NAME /*col2*/};

                Cursor c = managedQuery(uri2, projection, null, null, null);
                if (c!=null && c.moveToFirst()) {
                        name = c.getString(1);
                        Log.d("Display name",name);
                }
                c.close();
                if(!name.equals(""))
                {
                    if(name.toLowerCase().contains(".jpg"))
                    {
                        final LinearLayout ll3 = new LinearLayout(this);
                        ll3.setOrientation(LinearLayout.HORIZONTAL);
                        ll3.setLayoutParams(params);
                        ll.addView(ll3);
                        
                        LinearLayout ll4 = new LinearLayout(this);
                        ll4.setOrientation(LinearLayout.VERTICAL);
                        ll4.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
                        
                        final int id = cursor1.getInt(0);
                        
                        ImageView iv = new ImageView(this);
                        iv.setImageURI(uri2);
                        iv.setAdjustViewBounds(true);
                        iv.setMaxHeight(100);
                        iv.setMaxWidth(100);
                        iv.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                        iv.setClickable(true);
                        iv.setOnClickListener(new OnClickListener(){

                            @Override
                            public void onClick(View v) {
                                Intent i = new Intent(PicVid.this, Picture.class);
                                //create bundle and initialize
                                Bundle bundle = new Bundle();
                                //add parameters to bundle
                                bundle.putString("uri", uri2.toString());
                                //add bundle to the intent
                                i.putExtras(bundle);
                                startActivity(i);
                            }});
                        //((LinearLayout.LayoutParams) iv.getLayoutParams()).gravity = Gravity.CENTER;
                        ll3.addView(iv);
                        ll3.addView(ll4);
                        
                        TextView captionTitle = new TextView(this);
                        captionTitle.setText("Caption:");
                        ll4.addView(captionTitle);
                        
                        TextView caption = new TextView(this);
                        caption.setText(cursor1.getString(1));
                        ll4.addView(caption);
                        
                        final View ruler3 = new  View(this); 
                        ruler3.setBackgroundColor(0xFF909090);
                        ruler3.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 2));
                                          
                        ImageButton delImage = new ImageButton(this);
                        delImage.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                        delImage.setImageResource(R.drawable.delete);
                        delImage.setOnClickListener(new OnClickListener(){

                            @Override
                            public void onClick(View v) {
                                db.open();
                                db.deleteItem("picvid", id, iid);
                                db.close();
                                ll.removeView(ll3);
                                ll.removeView(ruler3);
                            }
                            
                        });
                        ((LinearLayout.LayoutParams) delImage.getLayoutParams()).gravity = Gravity.CENTER;
                        ll3.addView(delImage);
                        
                        ll.addView(ruler3);
                    }
                }
                cursor1.moveToNext();
            }
        }
        cursor1.close();
        db.close();
Code:
06-10 09:23:34.612: ERROR/AndroidRuntime(800): Uncaught handler: thread main exiting due to uncaught exception
06-10 09:23:34.622: ERROR/AndroidRuntime(800): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:375)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:212)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:663)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:641)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.widget.ImageView.resolveUri(ImageView.java:491)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.widget.ImageView.setImageURI(ImageView.java:287)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at  mobile.PicVid.onCreate(PicVid.java:202)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at  mobile.PicVid.onResume(PicVid.java:701)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1228)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.Activity.performResume(Activity.java:3542)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.LocalActivityManager.moveToState(LocalActivityManager.java:170)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.LocalActivityManager.dispatchResume(LocalActivityManager.java:518)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityGroup.onResume(ActivityGroup.java:58)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1228)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.Activity.performResume(Activity.java:3542)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2647)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2287)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3278)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.access$1900(ActivityThread.java:112)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.os.Handler.dispatchMessage(Handler.java:99)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.os.Looper.loop(Looper.java:123)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at android.app.ActivityThread.main(ActivityThread.java:3948)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at java.lang.reflect.Method.invokeNative(Native Method)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at java.lang.reflect.Method.invoke(Method.java:521)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
06-10 09:23:34.622: ERROR/AndroidRuntime(800):     at dalvik.system.NativeStart.main(Native Method)
 
Ok, so the problem is not having final in the code.

I edited the code to remove almost all the finals and the log still gives the same error.

The pictures still are not being released and I'm not sure why.

here is my new code

Code:
        db.open();
        Cursor cursor1 = db.getItemFromInfo("picvid", iid);
        if(cursor1.moveToFirst())
        {
            while(!cursor1.isAfterLast())
            {
                String name="";
                String uriString = cursor1.getString(2);
                final Uri uri2 = Uri.parse(uriString);
                
                String[] projection = { MediaStore.Images.ImageColumns.DATA, /*col1*/
                                MediaStore.Images.ImageColumns.DISPLAY_NAME /*col2*/};

                Cursor c = managedQuery(uri2, projection, null, null, null);
                if (c!=null && c.moveToFirst()) {
                        name = c.getString(1);
                        Log.d("Display name",name);
                } 
                c.close();
                
                if(!name.equals(""))
                {
                    if(name.toLowerCase().contains(".jpg"))
                    {
                        LinearLayout ll5 = new LinearLayout(this);
                        ll5.setOrientation(LinearLayout.VERTICAL);
                        ll5.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
                        ll.addView(ll5);
                        
                        LinearLayout ll3 = new LinearLayout(this);
                        ll3.setOrientation(LinearLayout.HORIZONTAL);
                        ll3.setLayoutParams(params);
                        ll5.addView(ll3);
                        
                        LinearLayout ll4 = new LinearLayout(this);
                        ll4.setOrientation(LinearLayout.VERTICAL);
                        ll4.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
                        
                        final int id = cursor1.getInt(0);
                        
                        ImageView iv = new ImageView(this);
                        iv.setImageURI(uri2);
                        iv.setAdjustViewBounds(true);
                        iv.setMaxHeight(100);
                        iv.setMaxWidth(100);
                        iv.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                        iv.setClickable(true);
                        iv.setOnClickListener(new OnClickListener(){

                            @Override
                            public void onClick(View v) {
                                Intent i = new Intent(PicVid.this, Picture.class);
                                //create bundle and initialize
                                Bundle bundle = new Bundle();
                                //add parameters to bundle
                                bundle.putString("uri", uri2.toString());
                                //add bundle to the intent
                                i.putExtras(bundle);
                                startActivity(i);
                            }});
                        //((LinearLayout.LayoutParams) iv.getLayoutParams()).gravity = Gravity.CENTER;
                        ll3.addView(iv);
                        ll3.addView(ll4);
                        
                        TextView captionTitle = new TextView(this);
                        captionTitle.setText("Caption:");
                        ll4.addView(captionTitle);
                        
                        TextView caption = new TextView(this);
                        caption.setText(cursor1.getString(1));
                        ll4.addView(caption);
                        
                        View ruler3 = new  View(this); 
                        ruler3.setBackgroundColor(0xFF909090);
                        ruler3.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 2));
                                          
                        ImageButton delImage = new ImageButton(this);
                        delImage.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                        delImage.setImageResource(R.drawable.delete);
                        delImage.setOnClickListener(new OnClickListener(){

                            @Override
                            public void onClick(View v) {
                                LinearLayout ll3 = (LinearLayout) v.getParent();
                                LinearLayout ll5 = (LinearLayout) ll3.getParent();
                                db.open();
                                db.deleteItem("picvid", id, iid);
                                db.close();
                                ll.removeView(ll5);
//                                ll.removeView(ll3);
//                                ll.removeView(ruler3);
                            }
                            
                        });
                        ((LinearLayout.LayoutParams) delImage.getLayoutParams()).gravity = Gravity.CENTER;
                        ll3.addView(delImage);
                        
                        ll5.addView(ruler3);
                    }
            }
                cursor1.moveToNext();
            }
        }
        cursor1.close();
        db.close();
 
Well first things first make sure you have the most recent drivers for your video card and all the updates for vista. SP1 should have fixed any memory leak issues. from what i'm seeing on the specs of it yeah you shouldn't have any problems with WoW now crysis and fear you probably are pushing it with only 2GB of RAM. I would leave the virtual RAM to be set by the system just tends to be better unless your dealing with a server.
 
As you've already worked out, declaring something as final or not is irrelevant to your problem, and has no effect on the amount of memory being used.

The comment about Vista and video drivers is also irrelevant, as it's Android that is running out of memory. (The fact that the emulator may be running on Vista makes no difference.)

The problem is that images and bitmaps use up a lot of memory, and in my experience I've managed to have 2 at the most before running out of memory (they were fairly big ones). You need to release the resource to free up the memory before you try to allocate any more.

Mark
 
How would I go about destructing the image when its set like this?

Code:
ImageView iv = new ImageView(this);
iv.setImageURI(uri2);

Also, I found a temporary work around but its not a permanent fix.

Code:
private BitmapFactory.Options options;
...
options=new BitmapFactory.Options();
options.inSampleSize = 8;
...
Bitmap preview = BitmapFactory.decodeFile(uriString, options);
ImageView iv = new ImageView(this);
//iv.setImageURI(uri2);
iv.setImageBitmap(preview);

It seems that since I shrink the image before doing anything with it I can load a lot of images and rotate as much as I want without reaching the memory cap. But I'm still not sure if these images are being released or not.

Thanks for any help.
 
Oof I thought it would be something simple like:

delete iv;

But I was looking around and it seems that Java is supposed to do this automatically for you -- it seems that the answer is to resize as you found, and then android will deallocate the memory when it's not needed. You might try to removeView(yourimageview) perhaps if you manually want to delete it.
 
Back
Top Bottom