Огромное использование памяти в уведомлениях - PullRequest
10 голосов
/ 31 августа 2010

Я разрабатываю приложение с сервисом, который показывает ход работы таймера в области уведомлений (с индикатором выполнения и текстом). Ниже приведен более простой пример с той же проблемой.

Код Сервиса:

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

Код 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);
    }
}

Проблема в огромном использовании памяти. Вот вывод logcat:

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

Я думаю, что это слишком много памяти, и через некоторое время телефон зависает с таким выводом:

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

Кто-нибудь знает, как я могу сделать это, не используя так много памяти?

Спасибо!

Ответы [ 4 ]

10 голосов
/ 19 декабря 2010

Я наткнулся на ту же проблему ... Похоже, что если я не "кэширую" RemoteView и уведомления в сервисе, но воссоздаю их с нуля в процедуре "обновления", эта проблема исчезает.Да, я знаю, что это неэффективно, но, по крайней мере, телефон не перезагружается через 10-15 минут, потому что ему не хватает памяти.

2 голосов
/ 31 августа 2010

Попробуйте использовать DDMS для выгрузки распределений - это должно показать вам, какие объекты выделяются и где.

Я предполагаю, что индикатор выполнения выделяет несколько битовых карт при каждом вызове setProgressBar (5 раз в секунду), и это то, что происходит в памяти. Что не ясно, так это то, почему у вас заканчивается время - GC, похоже, подхватывает его, поэтому что-то должно протекать.

1 голос
/ 18 января 2011

Проблема с этим обходным решением состоит в том, что, если это текущее уведомление, оно будет «прыгать» в строке состояния и панели уведомлений при обновлении других текущих уведомлений.

Я пробовал несколько вещей, в том числе объявлял члены RemoteView и Notification энергозависимыми (поскольку RemoteView является многопоточным), которые, казалось, работали, но только замедляли проблему.

Я остановился на использовании элемента-дросселя и "кэшировал" RemoteView и Notification до X раз, а затем воссоздал их.

Когда их элементы установлены в ноль, небольшая утечка, кажется, устранена.

0 голосов
/ 27 июля 2016

У меня была похожая проблема. У меня был Service, который представлял Notification с индикатором выполнения, который соответствовал загрузке файла. Приложение будет аварийно завершать работу с OutOfMemoryError, примерно через десять секунд после того, как пользователь нажмет на Notification, перенеся их в приложение.

Я обнаружил, что добавление .setOngoing(true); в Builder решило эту проблему.

public NotificationCompat.Builder setOngoing (булево выполняется)

Установите, является ли это текущим уведомлением. Текущие уведомления отличаются от обычных уведомлений следующими способами:

  • Текущие уведомления сортируются над обычными уведомлениями на панели уведомлений.

  • В текущих уведомлениях нет кнопки закрытия «X», и кнопка «Очистить все» не действует.

Пример:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setAutoCancel(true)
                                                         .setDefaults(Notification.DEFAULT_ALL)
                                                         .setContentTitle("Downloading").setContentText("Download in progress...)
                                                             .setSmallIcon(android.R.drawable.stat_sys_download)
                                                             .setSound(null)
                                                             .setDefaults(0)
                                                             .setOngoing(true);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...