Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Huge memory usage in notifications

I am developing an application with a service which show the progress of a timer in the notification area (with a progress bar and a text). I have extracted below a simpler example with the same problem.

The code of the Service:

public class TNService extends Service {
    private NotificationManager nm;
    private Notification notification;
    private RemoteViews remoteView;

    @Override
    public void onCreate () {
        nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        notification = new Notification(android.R.drawable.stat_sys_download, 
                "My notification", 
                System.currentTimeMillis());
        remoteView = new RemoteViews(this.getPackageName(),
                R.layout.notification);
        remoteView.setImageViewResource(R.id.icon, android.R.drawable.stat_sys_download);
        remoteView.setTextViewText(R.id.text, "");
        remoteView.setProgressBar(R.id.progress, 100, 0, false);
        notification.flags = Notification.FLAG_NO_CLEAR;
        notification.contentView = remoteView;
        notification.contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                TNActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);

        Timer timer = new Timer ();
        timer.schedule(new TNTask(this), 0, 200);
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    public void updateNotification(int progress) {
        remoteView.setProgressBar(R.id.progress, 1000, progress, false);
        remoteView.setTextViewText(R.id.text, "Progress: " + progress);
        nm.notify(0, notification);
    }
}

The code of the TimerTask:

public class TNTask extends TimerTask {
    private TNService service;
    private int progress;

    public TNTask(TNService s) {
        this.service = s;
        this.progress = 0;
    }

    @Override
    public void run() {
            progress = (progress + 1) % 1000;
        this.service.updateNotification (progress);
    }
}

The problem is the huge memory usage. Here is the logcat output:

D/dalvikvm(11985): GC_EXPLICIT freed 1258 objects / 84016 bytes in 1157ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 52216 objects / 1900968 bytes in 130ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 49465 objects / 1805248 bytes in 125ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 53106 objects / 1909992 bytes in 134ms
D/dalvikvm(12008): GC_EXPLICIT freed 1604 objects / 100944 bytes in 90ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 53011 objects / 1937160 bytes in 135ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 49806 objects / 1817992 bytes in 143ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 49016 objects / 1769536 bytes in 135ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 53509 objects / 1941064 bytes in 145ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 49895 objects / 1842312 bytes in 146ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 48728 objects / 1774496 bytes in 150ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 47557 objects / 1701976 bytes in 146ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 53540 objects / 1903808 bytes in 156ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 48997 objects / 1784048 bytes in 158ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 48326 objects / 1776864 bytes in 158ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 47566 objects / 1742488 bytes in 169ms
D/dalvikvm(   85): GC_FOR_MALLOC freed 47606 objects / 1703416 bytes in 170ms
D/dalvikvm(  162): GC_EXPLICIT freed 11238 objects / 641368 bytes in 1064ms

I think it is too much memory and after a while the phone hangs with this output:

D/dalvikvm(   85): GC_FOR_MALLOC freed 0 objects / 0 bytes in 241ms
I/dalvikvm-heap(   85): Clamp target GC heap from 24.008MB to 24.000MB
I/dalvikvm-heap(   85): Grow heap (frag case) to 24.000MB for 52-byte allocation
I/dalvikvm-heap(   85): Clamp target GC heap from 26.008MB to 24.000MB
D/dalvikvm(   85): GC_FOR_MALLOC freed 0 objects / 0 bytes in 241ms
I/dalvikvm-heap(   85): Clamp target GC heap from 24.008MB to 24.000MB
I/dalvikvm-heap(   85): Grow heap (frag case) to 24.000MB for 24-byte allocation
I/dalvikvm-heap(   85): Clamp target GC heap from 26.008MB to 24.000MB
D/dalvikvm(   85): GC_FOR_MALLOC freed 0 objects / 0 bytes in 247ms
I/dalvikvm-heap(   85): Clamp target GC heap from 24.009MB to 24.000MB
I/dalvikvm-heap(   85): Grow heap (frag case) to 24.000MB for 28-byte allocation
I/dalvikvm-heap(   85): Clamp target GC heap from 26.009MB to 24.000MB
D/dalvikvm(   85): GC_FOR_MALLOC freed 0 objects / 0 bytes in 247ms
I/dalvikvm-heap(   85): Clamp target GC heap from 24.009MB to 24.000MB

Anyone knows how can I do it without using so many memory?

Thanks!

like image 334
Urizev Avatar asked Aug 31 '10 11:08

Urizev


People also ask

Why is my memory usage suddenly so high?

Why is my memory usage so high in Windows 10? One reason could be a big program or game that takes high system RAM. The other reason could be malware that caused your device high memory usage.


3 Answers

I stumbled upon the same problem... It seems like that if I don't "cache" the RemoteView and Notification in the service, but re-create them from scratch in the "update" routine this problem disappears. Yes, I know it is not efficient, but at least the phone does not reboot after 10-15 minutes because it's out of memory.

like image 168
haimg Avatar answered Oct 16 '22 17:10

haimg


Try using DDMS to dump out the allocations - that should show you what objects are being allocated and where.

My guess is that the progress bar is allocating some bitmaps on every call to setProgressBar (5 times per second) and that's what's churning through memory. What's not clear is why you are then running out - the GC seems to be picking it up, so something must be leaking.

like image 34
Colin Stewart Avatar answered Oct 16 '22 17:10

Colin Stewart


The problem with this workaround is that if it's an ongoing notification, it will "hop" on the status bar and notification pane as other ongoing notifications are updated.

I've tried several things, including declaring the RemoteView and Notification members as volatile (because RemoteView is cross-thread), which seemed to work, but only slowed down the problem.

What I settled on was using a choke member, and "cacheing" the RemoteView and Notification up to X times, then recreating them.

When their members are set to null, the small leak seems to be freed.

like image 29
Android Dev Dude Avatar answered Oct 16 '22 15:10

Android Dev Dude