Збирач сміття в Android


108

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

Чи є гарною практикою запитувати сміттєзбірника в Android, перш ніж робити операцію, спогадну пам'ять? Якщо ні, чи варто мені дзвонити лише у випадку OutOfMemoryпомилки?

Чи є інші речі, які я повинен використовувати, перш ніж вдаватися до сміттєзбірника?

Відповіді:


144

Для версій до 3.0 сот : Так, телефонуйте System.gc() .

Я намагався створити Bitmaps, але завжди отримував "VM з помилки пам'яті". Але коли я зателефонував System.gc()першим, все було нормально.

Створюючи растрові карти, Android часто не вдається з помилками пам'яті, і не намагається спочатку збирати сміття . Отже, дзвоніть System.gc(), і у вас є достатньо пам’яті для створення бітових карт.

Якщо створювати Об'єкти, я думаю, System.gcбуде викликано автоматично, якщо це потрібно, але не для створення растрових зображень. Це просто не вдається.

Тому я рекомендую вручну зателефонувати System.gc()перед створенням растрових зображень.


39
Це пояснюється тим, що дані попередньої соти, растрові карти не зберігаються у ВМ, і тому це не запустить GC. Це не повинно бути проблемою в сотах і пізніше.
Timmmm

2
@Timmmm, але насправді це була моя проблема, я просто встановив bigheap на істину.
Лей Лейба

118

Взагалі кажучи, у присутності сміттєзбірника ніколи не є хорошою практикою вручну викликати ГК. GC організований навколо евристичних алгоритмів, які найкраще працюють, якщо залишити їх на власні пристрої. Виклик GC вручну часто знижує продуктивність.

Інколи , у деяких відносно рідкісних ситуаціях, можна виявити, що певний GC помиляється, і ручний виклик до GC може потім покращити результати, які залежать від продуктивності. Це тому, що реально реалізувати "ідеальний" GC, який буде керувати пам'яттю оптимально у всіх випадках, неможливо. Такі ситуації важко передбачити і залежать від багатьох тонких деталей реалізації. "Гарна практика" полягає в тому, щоб дозволити роботі GC самостійно; виняток вручну до GC - це виняток, який слід передбачати лише після належного засвідчення фактичної проблеми щодо ефективності.


8
+1 за гарну незалежну платформу відповідь. Чекаю, якщо хтось придумає відповідь, пов’язану з Android, перед тим, як вибрати.
hpique

8
Я згоден з тим, що ви написали, якщо ви дозволяєте "продуктивність" означати щось більш загальне, ніж ефективність процесора. На пристрої Android сприйняття користувачем продуктивності є першорядним. Розробник, можливо, вважає за краще запускати GC, поки користувач, наприклад, натискає кнопки, тому користувач не буде в курсі про GC.
Президент Джеймс К. Полк

5
У іграх часто важливо, щоб GC не працював під час гри (це вимагає, щоб усі об'єкти були попередньо створені та перероблені або подібні), але коли гра призупинена, це хороший час для GC.
Пт

4
Дані попередньої стінки, растрові дані не зберігаються у пам'яті VM. Система не виявить, коли ви використовували занадто багато пам'яті, що не VM, через бітові карти та запускає GC (що запускає Bitmap.finalize()методи, що звільняють пам'ять, що не VM). Тому в цьому випадку вам слід перейти через голову GC і бігти Bitmap.recycle()або, System.gc()де це доречно. Але тільки попередньо соти.
Тиммммм

1
@ThomasPornin - З іншого боку, як програміст програми ви знаєте щось, чого ОС не знає: часи, коли зараз ваш додаток буде внести серйозні зміни в тому, як він використовує пам'ять, і що це буде менш руйнівним для користувачеві зробити паузу зараз, ніж у довільний час у майбутньому . Це означає , що під час великих переходів у тому, як використовується програма, може бути розумним робити нечасті дзвінки . Вони рідкісні в тому сенсі, що не слід часто дзвонити в GC, але є загальним, що майже будь-яке значне додаток має такі відомі моменти дизайну.
ToolmakerSteve

26

Немає пам'яті в додатку для Android дуже часто, якщо ми не маємо належним чином обробляти растрову карту. Рішення проблеми було б

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

У наведеному вище коді Ви тільки що спробували переробити растрову карту, що дозволить вам звільнити використаний простір пам'яті, тому пам'ять може не трапитися. Я спробував, що це працювало на мене.

Якщо ви все ще стикаєтеся з проблемою, ви можете також додати ці рядки

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

для отримання додаткової інформації дивіться за цим посиланням

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


ПРИМІТКА. Через миттєву "паузу", спричинену виконанням gc, не рекомендується робити це перед кожним розподілом растрових зображень.

Оптимальний дизайн:

  1. Безкоштовні всі растрові карти, які більше не потрібні , за if / recycle / nullвказаним кодом. (Створіть метод, який допоможе в цьому.)

  2. System.gc();

  3. Виділіть нові растрові карти.


19

Якщо ви отримаєте OutOfMemoryError, тоді, як правило, пізно зателефонувати до сміттєзбірника ...

Ось цитата від Android Developer:

Здебільшого збирання сміття відбувається через багато дрібних, недовговічних предметів, а деякі сміттєзбірники, як-от покоління сміттєзбірників, можуть оптимізувати збір цих об’єктів, щоб додаток не перебивались занадто часто. Накопичувач сміття Android, на жаль, не в змозі здійснити подібні оптимізації, а створення короткочасних об'єктів у критичних кодових шляхах продуктивності дуже дорого вашої програми.

Отже, наскільки я розумію, немає нагальної потреби називати Gc. Краще витратити більше зусиль на те, щоб уникнути зайвого створення об’єктів (наприклад, створення об’єктів всередині циклів)


6
Чи не можна цитату трактувати інакше? Можливо, GC потрібно викликати вручну, щоб зібрати ці об'єкти, перш ніж вони забирають занадто багато пам'яті.
hpique

@hgpc: Я не бачу, як цитату можна інтерпретувати так, як ви пропонуєте. Я здогадуюсь, що документація - це зізнання, визнаючи, що їх GC проста; коли пам'ять втрачається, виконується повний GC.
Президент Джеймс К. Полк

Повне використання складних об'єктів та рамок із використанням складних об'єктів, як правило, краще використовувати час розробки, ніж передчасна оптимізація. Турбуватися з приводу оптимізації - це простіша пастка для Android, ніж для Enterprise Java, оскільки ми підсвідомо продовжуємо думати про продуктивність, кодуючи мобільний додаток. Тим більше, що розробники рамок, які повинні думати про ефективність, просочують цю точку зору в свою офіційну документацію, коли вони не обережні.
Латеральний фрактал

9

Здається, System.gc()це не працює на Art Android 6.0.1 Nexus 5x, тому я використовую Runtime.getRuntime().gc();натомість.


1
System.gc()є функцією обгортки для Runtime.getRuntime().gc(). Дивіться android.googlesource.com/platform/libcore/+/…
Натан Ф.

Так, з джерела та документації виглядає так, що вони однакові, але насправді System.gc()не працює для мене, але Runtime.getRuntime().gc()так!
Іван

7

У моїй програмі працює багато зображень, і вона загинула за допомогою OutOfMemoryError. Це мені допомогло. У Manifest.xml Додати

<application
....
   android:largeHeap="true"> 

9
Google це не любить
Педро Паулу Аморім

1
@PedroPauloAmorim поясніть чому?
Мачадо

2
Не використовуйте великийHeap, якщо ви не впевнені, що робите. Використання великих наборів змушує роботу сміттєзбірника набагато важче, оскільки йому доведеться перебирати багато небажаних даних, перш ніж очистити пам'ять.
Пракаш

7

Взагалі, ви не повинні викликати GC явно за допомогою System.gc (). Існує навіть лекція з IO ( http://www.youtube.com/watch?v=_CruQY55HOk ), де вони пояснюють, що означає журнал пауз GC і в якому вони також заявляють, що ніколи не викликають System.gc (), оскільки Далвік знає краще ніж ти, коли це робити.

З іншого боку, як згадувалося вище, відповіді вже на процес GC в Android (як і в усьому іншому) іноді бувають помилки. Це означає, що алгоритми Dalvik GC не нарівні з хотспотом або JRockit JVM, а в деяких випадках можуть вийти з ладу. Один із таких випадків - при розподілі растрових об'єктів. Цей складний, оскільки він використовує пам'ять Heap та Non Heap і тому, що одного вільного екземпляра об'єкта растрових зображень на пристрої з обмеженою пам’яттю достатньо, щоб отримати виняток OutOfMemory. Тому називати його після того, як вам більше не потрібна ця растрова карта, як правило, пропонується багатьма розробниками, і деякі люди навіть вважають хорошою практикою.

Кращою практикою є використання .recycle () у растровій карті, оскільки саме для цього створено цей метод, оскільки він позначає рідну пам'ять растрової карти як безпечну для видалення. Майте на увазі, що це дуже залежить від версії, тобто, як правило, це потрібно для старих версій Android (я думаю, що передує 3.0), але на пізніших версіях не потрібно. Крім того, це не зашкодить, використовуючи його на новіших версіях ефіру (просто не робіть цього в циклі чи щось подібне). Новий час виконання ART тут сильно змінився, оскільки вони запровадили спеціальний «розділ» для великих об'єктів, але я думаю, що це не завадить зробити це з ефіром ART.

Також одна дуже важлива примітка про System.gc (). Цей метод не є командою, на яку Далвік (або JVM) зобов'язаний відповідати. Розгляньте це більше, як сказати віртуальній машині "Не могли б ви зробити сміття, якщо це не клопоту".



3

Я б сказав "ні", оскільки розробник документує стан використання оперативної пам'яті :

...
GC_EXPLICIT

Явний GC, наприклад, коли ви викликаєте gc () (який слід уникати дзвінків і замість цього довіряти GC запускатися, коли це потрібно).

...

Я виділив відповідну частину жирним шрифтом.

Погляньте на серію YouTube, шаблони продуктивності Android - вона покаже вам поради щодо управління використанням пам’яті вашого додатка (наприклад, використання Android ArrayMapі SparseArrays замість HashMaps).


3

Коротка примітка для розробників Xamarin .

Якщо ви хочете зателефонувати System.gc()у програми Xamarin.Android, вам слід зателефонуватиJava.Lang.JavaSystem.Gc()


2

Немає необхідності викликати сміттєзбірник після OutOfMemoryError.

У Javadoc чітко зазначено:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Так, сміттєзбірник вже намагався звільнити пам'ять, перш ніж створити помилку, але виявився невдалим.


8
Android Javadoc цього не говорить, і, швидше за все, його реалізація відрізняється. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique

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