Які інструменти та методи Android найкраще працюють для пошуку витоків пам'яті / ресурсів? [зачинено]


152

У мене розроблено додаток для Android, і я перебуваю на етапі розробки додатків для телефону, де все, здається, працює добре, і ви хочете оголосити перемогу і відправити, але ви знаєте, що там просто повинно бути кілька витоків пам'яті та ресурсів. там; а на Android лише 16 Мбайт купи, і це, начебто, напрочуд легко протікає в додатку для Android.

Я озирався, і поки що мені вдалося лише перекопати інформацію про "hprof" і "traceview", і жоден не отримав багато сприятливих відгуків.

Якими інструментами чи методами ви натрапили чи розробили і хочете поділитися, можливо, у проекті ОС?


3
Чи можу я проголосувати за те, щоб РȢѸСТȢѸ́ФХѾЦЧШЩЬЫЮѢѤѢѤЮѦѪѨѬѠѺѮѰѲѴ змінив своє ім’я на щось читабельне.
JPM

1
було б добре знову відкрити це запитання, якщо ми видалимо слово "Інструменти Android" із питання-заголовка? Знайдені тут відповіді були досить корисними для вирішення моїх проблем із витоком пам’яті
k3b

Гаразд, тому у мене користувач постійно перемикається між видами діяльності, тобто вони можуть переключити 15 заходів за 20 секунд. Чи може це бути причиною помилки в пам'яті? Що мені робити, щоб це виправити? Дякую!
Ручір Баронія

1
Не можу надати це як відповідь, оскільки питання було закрито, проте я рекомендую поглянути на " Утечку Канар" . Просто використовуйте додаток, відкривайте та закривайте діяльність, і дозвольте бібліотеці робити свою роботу. Він навіть розповість про те, де відбувся витік. Просто дайте аналізатору витоку деякий час, щоб виконати свою роботу після виникнення витоку - зазвичай це займає приблизно 2 хвилини або більше, поки джерело витоку не буде знайдено. Після цього він представить вам його акуратно в додатку. Не потрібні додаткові інструменти!
ubuntudroid

Відповіді:


90

Однією з найпоширеніших помилок, яку я виявив, розробляючи програми для Android, є помилка "java.lang.OutOfMemoryError: Розмір растрової карти перевищує бюджет VM". Я часто виявляв цю помилку в діяльності з використанням безлічі растрових зображень після зміни орієнтації: активність знищується, створюється знову, а макети «надуваються» від XML, що споживає пам'ять VM, доступну для растрових зображень.

Збірник сміття не містить належних зображень на попередньому макеті діяльності, оскільки вони перекреслили посилання на свою діяльність. Після багатьох експериментів я знайшов досить вдале рішення цієї проблеми.

Спочатку встановіть атрибут "id" на батьківському поданні вашого макета XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

Потім за допомогою методу onDestroy () вашої діяльності викличте метод unbindDrawables (), який передасть референс батьківському виду, а потім зробіть System.gc ()

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

Цей метод unbindDrawables () рекурсивно досліджує дерево перегляду та:

  1. Видаляє зворотні дзвінки на всіх фонових рисунках
  2. Вилучає дітей із кожної групи перегляду

3
Гарне рішення поширеної проблеми.
Хоча-Е

9
Це не працює для підкласів AdapterView (ListView, GridView тощо).
Арджун

@ Арджун Так ... це не працює для AdapterView підкласів. Для цього потрібно обробляти виняток. Відпочинок це прекрасно працює. Це те, що я використовую в своєму коді, і він прекрасно працює. Сподіваюся, це допомагає.
hp.android

@ hp.android "Ви можете вирішити це за винятком", чи є у вас приклад того, як це могло б виглядати? Я запитую, оскільки у мене є сторінки із зображеннями, PageAdapterі я
переживаю

4
@Jackson просто змініть умову: якщо (перегляньте instanceof ViewGroup &&! (Перегляньте instanceof AdapterView)) це позбудеться виключення, яке ви отримуєте для Adapter
hp.android


28

Переважно для подорожуючих Google з майбутнього:

На жаль, більшість інструментів java, на жаль, не підходять для цього завдання, оскільки вони аналізують лише JVM-Heap. Кожен додаток для Android також має вроджену групу, яка також повинна відповідати межі ~ 16 Мб. Зазвичай використовується, наприклад, для растрових даних. Таким чином, ви можете легко запускати помилки Out Of Memory, навіть якщо ваш JVM-Heap чиліном близько 3 Мбайт, якщо ви використовуєте велику кількість чернет.


6
стартові Android 3.0 (
сотові) малюнки

@ Тимо, що б ви використовували для виявлення витоків у рідній купі?
sydd

1
Тестування, багато тестування. Проблема полягає в тому, що ви навіть не можете точно сказати, скільки пам’яті використовує ваше додаток, завдяки обміну пам’яттю та іншими методами оптимізації. Ви можете отримати показання пам'яті за допомогою звичайних команд оболонки, але це дуже, дуже грубі оцінки.
Тімо Охр

20

Відповідь від @ hp.android добре працює, якщо ви просто працюєте з фоном растрових зображень, але, в моєму випадку, у мене був BaseAdapterнабір ImageViews для a GridView. Я змінив unbindDrawables()метод, як радили, щоб умова:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

але проблема полягає в тому, що рекурсивний метод ніколи не обробляє дітей AdapterView. Щоб вирішити це, я натомість зробив наступне:

if (view instanceof ViewGroup) {
  ViewGroup viewGroup = (ViewGroup) view;
  for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

  if (!(view instanceof AdapterView))
    viewGroup.removeAllViews();
}

щоб діти AdapterViewвсе ще оброблялися - метод просто не намагається видалити всіх дітей (що не підтримується).

Однак це не зовсім вирішує проблему, оскільки ImageViewкеруємо растровою картою, яка не є їхнім фоном. Тому я додав наступне. Це не ідеально, але це працює:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

Загальний unbindDrawables()метод тоді:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else if (view instanceof ViewGroup) {
    ViewGroup viewGroup = (ViewGroup) view;
    for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

    if (!(view instanceof AdapterView))
      viewGroup.removeAllViews();
  }
}

Я сподіваюся, що існує більш принциповий підхід до звільнення таких ресурсів.


12

Гарна розмова Google I / O (2011) про управління пам’яттю в Android, а також деталі щодо інструментів + ​​методів профілювання пам'яті:
http://www.youtube.com/watch?v=_CruQY55HOk


4
Або відповідне повідомлення в блозі: android-developers.blogspot.com/2011/03/…
greg7gkb

1
Гаразд, тому у мене користувач постійно перемикається між видами діяльності, тобто вони можуть переключити 15 заходів за 20 секунд. Чи може це бути причиною помилки в пам'яті? Що мені робити, щоб це виправити? Дякую!'
Рухір Баронія


1

Ну, це інструменти, які підключаються до унікальних форматів, які використовує Android. Я думаю, що ви можете бути незадоволені - це основна система тестування коду, що використовується.

Ви пробували макет тестування областей коду за допомогою Android Mock Framework?


1
не так багато, тестування такого характеру полягає не стільки в проблемі, скільки в записі того, що насправді відбувається під час роботи програми, що мені дійсно потрібно, це інструмент для профілювання витоку ресурсів / пам'яті
jottos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.