Резюме утечки памяти Android
Цель управления памятью состоит в том, чтобы помочь нам эффективно избежать утечек памяти в наших приложениях во время разработки. Все знакомы с утечками памяти. Проще говоря, это означает, что объект, который должен быть выпущен, не был выпущен, и был удерживается определенным экземпляром, но больше не используется, так что GC не может быть переработан. Недавно я прочитал много соответствующих документов и материалов. Я планирую суммировать и урегулировать их, поделиться и учиться с вами, а также предоставлять себе предупреждение о том, как избежать этих ситуаций во время кодирования в будущем и улучшить опыт и качество приложения.
Я начну с оснований утечек памяти Java и использую конкретные примеры, чтобы проиллюстрировать различные причины утечек памяти Android, а также того, как использовать инструменты для анализа утечек памяти приложения, и, наконец, суммировать их.
Стратегия распределения памяти Java
Существует три типа стратегии распределения памяти, когда работают программы Java, а именно статическое распределение, распределение стеков и распределение кучи. Соответственно, пространство памяти, используемые тремя стратегиями хранения, в основном статическая область хранения (также известная как область метода), область стека и область кучи.
Статическая область хранения (область метода): в основном хранят статические данные, глобальные статические данные и константы. Этот кусок памяти выделяется, когда программа составлена и существует на протяжении всего запуска программы.
Область стека: Когда метод выполняется, локальные переменные в корпусе метода (включая основной тип данных и ссылку на объект) создаются в стеке, а память, хранящаяся этими локальными переменными, будет автоматически выпущена в конце выполнения метода. Поскольку операция распределения памяти стека встроена в набор инструкций процессора, она очень эффективна, но выделенная емкость памяти ограничена.
Область кучи: также известная как распределение динамической памяти, обычно относится к памяти, которая является непосредственно новой, когда программа работает, то есть экземпляр объекта. Когда эта часть памяти не используется, сборщик мусора Java будет отвечать за переработку.
Разница между стеком и кучей:
Некоторые основные типы переменных, определенных в организме метода, и эталонные переменные объектов выделяются в памяти стека метода. Когда переменная определена в блоке метода, Java будет выделять пространство памяти для переменной в стеке. Когда объем переменной будет превышен, переменная будет недействительной, а распределенное на нее пространство памяти будет освобождено, а пространство памяти может быть использовано повторно.
Хиповая память используется для хранения всех объектов, созданных новыми (включая все переменные элемента в объекте) и массивы. Память, выделенная в куче, будет автоматически управляться коллекционером мусора Java. После того, как массив или объект генерируется в куче, в стеке можно определить специальную переменную. Значение этой переменной равно первому адресу массива или объекта в памяти кучи. Эта специальная переменная является эталонной переменной, которую мы упомянули выше. Мы можем получить доступ к объектам или массивам в куче через эту эталонную переменную.
Например:
Образец публичного класса {int s1 = 0; sample msample1 = new sample (); public void method () {int s2 = 1; образец msample2 = new sample ();}} sample msample3 = new sample (); Локальная переменная S2 класса выборки и эталонная переменная MSAMEMPL2 существуют в стеке, но объект, на который указан MSAMEPLO2 на куче.
Сущность объекта, на которую указано Msample3, хранится на куче, включая все переменные элемента S1 и MSAMEPLE1 этого объекта, и он существует в стеке.
в заключение:
Основные типы данных и ссылки локальных переменных хранятся в стеке, а в куче хранятся ссылочные объекты. - Поскольку они принадлежат к переменным методам, жизненный цикл заканчивается методами.
Все переменные -члены хранятся и в куче (включая основные типы данных, ссылочные и ссылочные объекты объектов) - поскольку они принадлежат классам, объекты класса в конечном итоге будут использоваться для нового использования.
После понимания распределения памяти Java, давайте посмотрим, как Java управляет памятью.
Как Java управляет памятью
Управление памятью Java - это проблема распределения объектов и выпуска. В Java программисты должны применить к пространству памяти для каждого объекта через новое ключевое слово (за исключением основных типов), и все объекты выделяют пространство в куче (куча). Кроме того, выпуск объектов определяется и выполняется GC. В Java распределение памяти осуществляется программами, в то время как выпуск памяти осуществляется GC. Этот метод дохода и расходов на двух строках упрощает работу программистов. Но в то же время это также добавляет к работе JVM. Это также одна из причин, по которой программы Java работают медленнее. Потому что, чтобы правильно освободить объекты, GC должен отслеживать состояние выполнения каждого объекта, включая приложение, цитирование, цитирование, назначение и т. Д. Объекта, а GC должен его контролировать.
Мониторинг состояния объекта состоит в том, чтобы более точно и своевременно выпустить объект, а фундаментальный принцип освобождения объекта заключается в том, что объект больше не ссылается.
Чтобы лучше понять, как работает GC, мы можем считать объект как вершину направленного графика, а также эталонные отношения как направленные ребра графика, которые указывают от референтора к указанному объекту. Кроме того, каждый объект потока может использоваться в качестве начальной вершины графика. Например, большинство программ начинается с основного процесса, поэтому график представляет собой корневое дерево, начинающееся с основной вершины процесса. На этом направленном графике объекты, достижимые корневым вершиной, являются допустимыми объектами, и GC не будет перерабатывать эти объекты. Если объект (подключенный подграф) недоступен от этой корневой вершины (обратите внимание, что график представляет собой направленный график), то мы считаем, что этот (эти) объект больше не ссылается и может быть переработан GC.
Ниже мы приводим пример того, как использовать направленные графики для представления управления памятью. На каждый момент программы у нас есть направленный график, представляющий распределение памяти JVM. На рисунке ниже представлена диаграмма программы слева, работающей до строки 6.
Java использует направленные графики для управления памятью, которые могут устранить проблему эталонных циклов. Например, есть три объекта, которые относятся друг к другу. Пока они и корневой процесс недоступны, GC также может перерабатывать их. Преимущество этого метода заключается в том, что он обладает высокой точностью в управлении памятью, но является низкой эффективностью. Другая часто используемая технология управления памятью - использовать счетчики. Например, модель COM использует метод счетчика для управления компонентами. По сравнению с направленными графиками, он имеет низкую точность линии (трудно справиться с круговыми эталонными задачами), но обладает высокой эффективностью выполнения.
Что такое утечка памяти на Java
В Java утечки памяти - это существование некоторых выделенных объектов, которые имеют следующие две характеристики. Во -первых, эти объекты доступны, то есть на направленном графике есть пути, которые могут быть подключены к ним; Во -вторых, эти объекты бесполезны, то есть программа больше не будет использовать эти объекты в будущем. Если объект соответствует этим двум условиям, эти объекты могут быть определены как утечка памяти в Java, и эти объекты не будут переработаны GC, но он занимает память.
В C ++ утечки памяти имеют больший диапазон. Некоторые объекты выделяются пространством памяти, но затем недоступны. Поскольку в C ++ нет GC, эта память никогда не будет собрана. В Java эти недоступные объекты переработаны GC, поэтому программистам не нужно рассматривать эту часть утечки памяти.
Благодаря анализу мы знаем, что для C ++ программисты должны самостоятельно управлять краями и вершинами, в то время как для программистов Java им нужно только управлять краями (нет необходимости управлять выпуском вершин). Таким образом, Java повышает эффективность программирования.
Поэтому, благодаря приведенному выше анализу, мы знаем, что в Java также есть утечки памяти, но область применения меньше, чем у C ++. Поскольку Java Language гарантирует, что любой объект может быть достижимы, все недоступные объекты управляются GC.
Для программистов GC в основном прозрачен и невидим. Хотя у нас есть только несколько функций для доступа к GC, например, System.gc (), который запускает GC, в соответствии с определением спецификации языка Java, эта функция не гарантирует, что коллекционер мусора JVM выполнит. Потому что разные реализователи JVM могут использовать разные алгоритмы для управления GC. Как правило, потоки GC имеют более низкий приоритет. Есть много стратегий для JVM, чтобы вызвать GC. Некоторые из них начинают работать только тогда, когда использование памяти достигает определенного уровня. Некоторые выполняют их регулярно. Некоторые выполняют GC плавно, а некоторые выполняют GC в манере прерывания. Но, вообще говоря, нам не нужно заботиться об этом. Если в некоторых конкретных ситуациях выполнение GC влияет на производительность приложения. Например, для веб-систем в реальном времени, таких как онлайн-игры, пользователи не хотят, чтобы GC внезапно прерывал выполнение приложений и выполняла сбор мусора, тогда нам необходимо скорректировать параметры GC, чтобы GC мог свободно воспроизводить память, такую как разложение сбора мусора в серию небольших шагов для выполнения. Hotspot JVM, предоставленная Sun, поддерживает эту функцию.
Также дает типичный пример утечки памяти Java.
Вектор v = новый вектор (10); для (int i = 1; i <100; i ++) {object o = new Object (); v.Add (o); o = null; }В этом примере мы применяем к циклу объекта объекта и помещаем применяемый объект в вектор. Если мы только выпустим саму ссылку, вектор все еще ссылается на объект, поэтому этот объект не подлежит переработке для GC. Следовательно, если объект должен быть удален из вектора после того, как он добавлен в вектор, самый простой способ - установить векторный объект в NULL.
Утечка памяти в подробной Java
1. Механизм переработки памяти Java
Независимо от метода распределения памяти любого языка, необходимо вернуть реальный адрес выделенной памяти, то есть вернуть указатель на первый адрес блока памяти. Объекты в Java создаются с использованием новых методов или отражения. Создание этих объектов выделяется в куче. Все объекты собираются виртуальной машиной Java с помощью механизма сбора мусора. Чтобы правильно освободить объекты, GC будет контролировать состояние здоровья каждого объекта и контролировать их приложение, цитирование, цитирование, назначение и т. Д. Java будет использовать направленные методы графика для управления памятью, чтобы контролировать, может ли объект быть достигнут в режиме реального времени. Если он не будет достигнут, он будет переработан, что также может устранить проблему эталонных циклов. На языке Java существует два типа пространства памяти, которые определяют, соответствует ли пространство памяти критериям сбора мусора: один из них - назначить пустое значение объекту, которое не было вызвано ниже, а другой - присвоить новое значение объекту, тем самым перераспределяя пространство памяти.
2. Причины утечки памяти Java
Утечка памяти относится к непрерывному бесполезному объекту (объект, который больше не используется), или память о бесполезных объектах не может быть высвобождена во времени, что приводит к отходу пространства памяти, которое называется утечкой памяти. Утечки памяти иногда не являются серьезными и нелегкими для обнаружения, поэтому разработчики не знают, что есть утечка памяти, но иногда она может быть очень серьезной и вытесняет вас из памяти.
Какова основная причина утечки памяти Java? Если объект с длинным циклом содержит ссылку на объект цикла короткого срока жизни, вполне вероятно, что утечка памяти произойдет. Хотя объект с коротким циклом больше не нужен, его нельзя переработать, поскольку он содержит свою ссылку на длительный цикл. Это сценарий, когда утечки памяти происходят на Java. Есть в основном следующие категории:
1. Статический класс коллекции вызывает утечку памяти:
Использование Hashmap, Vector и т. Д. Скорее всего, в утечках памяти. Жизненный цикл этих статических переменных согласуется с применением. Все объекты, на которые они ссылаются, не могут быть опубликованы, потому что они также будут ссылаться на вектор и т. Д.
Например
Статический вектор v = новый вектор (10); для (int i = 1; i <100; i ++) {object o = new Object (); v.Add (o); o = null;}В этом примере объект объект применяется, а применяемый объект помещается в вектор. Если сама ссылка выпускается только (O = null), вектор все еще ссылается на объект, поэтому этот объект не подлежит переработке для GC. Следовательно, если объект должен быть удален из вектора после того, как он добавлен в вектор, самый простой способ - установить векторный объект в NULL.
2. Когда свойства объекта в сборе изменяются, метод remove () не будет работать.
Например:
Public Static void Main (String [] args) {set <Entry> set = new Hashset <ersont> (); человек P1 = новый человек («Tang Monk», «pwd1», 25); человек P2 = новый человек («Sun wukong», «Pwd2», 26); человек P3 = новый человек ("Zhu", "Pwd2", 26); человек = новый человек ("Zhu", "pwd2", 26); Bajie "," pwd3 ", 27); set.add (p1); set.add (p2); set.add (p3); System.out.println (" Есть общее количество элементов: "+set.size ()+"); // Результат: в общей сложности: 3 элемента! P3.Setage (2); // Измените возраст P3 и значение HashCode, соответствующее изменениям элемента P3 в это время SET.REMOVE (P3); // Удалить его в это время, вызывая набор утечек памяти. ADD (P3); // Добавить его снова, и он был успешно добавлен System.out.println («Есть:»+set.size ()+«элементы!»); // Результат: всего: 4 элемента! для (Person Person: set) {System.out.println (Person);}}3. Слушатель
В Java Programming нам всем нужно иметь дело со слушателями. Обычно в приложении используются многие слушатели. Мы будем называть метод управления, такой как addxxxlistener (), чтобы добавить слушателей, но часто, когда выпускаем объект, мы не помним, чтобы удалить этих слушателей, тем самым увеличивая вероятность утечек памяти.
4. Различные соединения
Например, подключение к базе данных (dataSury.getConnection ()), сетевое соединение (сокет) и подключения ввода -навода не будут автоматически переработаны GC, если оно явно не вызовет свой метод Close (), чтобы закрыть соединение. Объекты результатов и операторов не могут быть явно переработаны, но соединение должно быть явно переработано, поскольку соединение не может быть автоматически переработано в любое время. После того, как соединение будет переработано, объекты результатов и операторов будут немедленно нулевы. Однако, если вы используете пул соединений, ситуация отличается. В дополнение к явному закрытию соединения, вы также должны явно закрыть объект оператора Resultset (закрытие одного из них, другой также будет закрыт), в противном случае большое количество объектов оператора не будет выпущено, что приведет к утечкам памяти. В этом случае соединение обычно будет выпущено в попытке и наконец.
5. Ссылки на внутренние классы и внешние модули
Ссылки на внутренние классы относительно легко забыть, и как только они не будут выпущены, серия объектов преемника класса не может быть выпущена. Кроме того, программисты также должны быть осторожны с непреднамеренными ссылками на внешние модули. Например, программист A отвечает за модуль A и вызывает метод модуля B, такой как:
public void RegistryMsg (объект B);
Этот вид звонка требует большой ухода. Когда объект передается, вполне вероятно, что модуль B сохранит ссылку на объект. В настоящее время вам необходимо обратить внимание на то, предоставляет ли модуль B соответствующие операции для удаления ссылок.
6. Синглтон режим
Неверное использование синглтонского рисунка является распространенной проблемой, которая вызывает утечки памяти. Объекты Singleton будут существовать на протяжении всего жизненного цикла JVM после инициализации (в форме статических переменных). Если объект Singleton содержит внешние ссылки, то этот объект не будет переработан нормально JVM, что приведет к утечкам памяти. Рассмотрим следующий пример:
Класс a {public a () {b.getinstance (). seta (this);} ....} // класс B использует класс Singleton Mode B {private a A; private Static B () new B (); public b () {} public static b getInstance () {return antest;} public void seta (a) {this.a = a;/} gateTer ...} gateTter ...} gTeTter ...} gatTter ...} gTeTTER ...}Очевидно, что B принимает синглтонский шаблон, который содержит ссылку на объект A, и объект этого класса A не будет переработан. Представьте, что произойдет, если бы был более сложный объект или тип сбора
Сводка общих утечек памяти в Android
Утечка класса коллекции
Если у класса сбора есть только метод для добавления элементов и не имеет соответствующего механизма удаления, память будет занята. Если этот класс сбора является глобальной переменной (такой как статические свойства в классе, глобальная карта и т. Д., То есть существует статическая ссылка или окончательное указание на нее все время), то нет соответствующего механизма удаления, который может привести к увеличению памяти, а не уменьшаться. Например, типичный пример выше - одна из этих ситуаций. Конечно, мы определенно не будем писать такой 2B -код в проекте, но это все еще легко случиться, если мы не будем осторожны. Например, нам всем нравится делать некоторые кэши через HashMap, поэтому мы должны быть более осторожны в этой ситуации.
Утечка памяти, вызванная синглтонами
Поскольку статический природа синглтона делает свой жизненный цикл до тех пор, пока жизненный цикл приложения, если он используется ненадлежащим образом, легко вызвать утечку памяти. Например, следующий типичный пример,
Public Class Appmanager {Private Static Appmanager Extance; контекст частного контекста; Private Appmanager (контекст контекста) {this.context = context;} public Static Appmanager getInstance (контекст контекста) {if (exante == null) {exante = new Appmanager (context);} return Encement;}}Это нормальный синглтон. При создании этого синглтона, поскольку необходимо передать контекст, длина жизненного цикла этого контекста имеет решающее значение:
1. Если в настоящее время контекст применения проходит, потому что жизненный цикл применения - это жизненный цикл всего приложения, проблем не будет.
2. Если контекст деятельности передается в это время, когда деятельность, соответствующая этому контексту, уходит, поскольку ссылка на контекст удерживается объектом Singleton, его жизненный цикл равен всем жизненному циклу приложения, поэтому, когда деятельность выходит, его память не будет переработана, что вызывает утечку.
Правильный способ следует изменить на следующее:
открытый класс Appmanager {private Static Appmanager Extance; контекст частного контекста; private Appmanager (контекст контекста) {this.context = context.getApplicationContext (); // Контекст с использованием приложения} public Static Appmanager getInstance (context context) {if (exance == null) {exante = new Appmanager (context);} return Exatures;}}}}}}}}}}}}}}}}}}}}}}}}}}Или напишите таким образом, и вам даже не нужно передавать контекст в:
Добавьте статический метод в ваше приложение, GetContext () возвращает контекст приложения.
...
context = getApplicationContext (); .../*** получить глобальный контекст*@return return return global context объект*/public static context getContext () {return Context;} public Class Appmanager {private Static Appmanager; контекст частного контекста; Private Appmanager () {this.context = myApplication.getContext (); // context} public Static Applanage getInstance (). New Appmanager ();} return Encement;}}Анонимные внутренние классы/нестатические внутренние классы и асинхронные потоки
Утечка памяти, вызванная созданием статических экземпляров в нестатических внутренних классах
Иногда мы можем начать занятия часто. Чтобы не повторно создавать те же ресурсы данных, этот способ написания может произойти:
открытый класс MainActivity расширяет AppCompatactivity {Private Static TestResource mresource = null; @OverrideProtected void Oncreate (Bundle SavedInStanceState) {super.Oncreate (savedInstanceState); setContentView (r.layout.Activity_main); если (mmanager); nul Testresource ();} // ...} class testresource {// ...}}Это создает синглтон нестатического внутреннего класса внутри деятельности, и данные синглтона используются каждый раз, когда начинается деятельность. Хотя повторяющееся создание ресурсов избегается, это написание вызывает утечки памяти, поскольку нестатический внутренний класс будет иметь ссылки на внешние классы по умолчанию, а нестатический внутренний класс создаст статический экземпляр, а жизненный цикл экземпляра-столько же, сколько применение, которое приводит к тому, что статический экземпляр всегда придерживается ссылок на деятельность, что приводит к ресурсам памяти, которые не могут быть перечислены нормально. Правильный способ сделать это:
Установите внутренний класс в качестве статического внутреннего класса или извлеките внутренний класс и инкапсулируйте его в синглтон. Если вам нужно использовать контекст, пожалуйста, следуйте вышеуказанному контексту для использования приложения. Конечно, контекст приложения не является всемогущим, поэтому его нельзя использовать случайным образом. В некоторых местах вы должны использовать контекст деятельности. Сценарии применения контекста применения, обслуживания и деятельности следующие:
Где: №1 означает, что приложение и служба могут запустить деятельность, но необходимо создать новую очередь задач. Для диалога это может быть создано только в активности
Анонимный внутренний класс
Разработка Android часто наследует реализацию активности/фрагмента/представления. В настоящее время, если вы используете анонимные классы и удерживаются асинхронными потоками, будьте осторожны. Если нет меры, это определенно приведет к утечке.
Открытый класс MainActivity Extance Activity {... runnable Ref1 = new MyRunable (); Runnable Ref2 = new Runnable () {@OverridePublic void run () {}}; ...}Разница между Ref1 и Ref2 заключается в том, что Ref2 использует анонимные внутренние классы. Давайте посмотрим на память, на которую ссылаются во время выполнения:
Как видите, Ref1 не является чем -то особенным.
Но есть дополнительная ссылка в объекте реализации анонимного класса Ref2:
Эта ссылка на $ 0 указывает на MainActivity. Это, то есть текущий экземпляр MainActivity будет проводиться Ref2. Если эта ссылка передается в асинхронную поток, и этот поток и этот жизненный цикл активности являются непоследовательными, возникнет утечка активности.
Утечка памяти, вызванная обработчиком
Проблема утечки памяти, вызванная использованием обработчика, должна считаться наиболее распространенной. Чтобы избежать ANR, мы не выполняем трудоемкие операции в основном потоке и используем обработчик для обработки сетевых задач или инкапсуляют некоторые обратные вызовы и другие API. Однако обработчик не всемогущий. Если код обработчика записан стандартизированным образом, он может вызвать утечки памяти. Кроме того, мы знаем, что обработчик, сообщение и MessageQueue связаны друг с другом. В случае, если сообщение, отправленное Handler, еще не обработано, сообщение и объект Handler, который отправил его, будут удерживаться Tread question.
Поскольку Handler принадлежит переменным TLS (локальный хранение), жизненный цикл и деятельность непоследовательны. Следовательно, этот метод реализации, как правило, трудно гарантировать, что он согласуется с жизненным циклом представления или деятельности, поэтому легко вызвать правильный выпуск.
Например:
Проблема пробы открытого класса расширяет Activity {Private Final Handler MleakyHandler = new Handler () {@OverridePublic void handlemessage (сообщение msg) {// ...}}@everdeproted void ontreate (Bundle SavedinStanceste) {Super.Oncreate (SavedInstance); minots.mleakyhandler.postdelayed (new Runnable () {@OverridePublic void run () {/ * ... */}}, 1000 * 60 * 10); // вернуться к предыдущему Activation.finish ();}}Сообщение, отложенное задержанное выполнение 10 минут, объявлено в пробоочевидном отношении, и MLEAKYHandler вталкивает его в Queue Queue Когда деятельность будет отбрасываться в соответствии с Finise (), сообщение, которое задерживает выполнение задачи, будет продолжать существовать в основном потоке, в котором содержится ссылка на обработчика деятельности, поэтому деятельность, упавшая в Finish (), не будет переработана, вызывая утечку памяти (потому что обработчик является нестатическим внутренним классом, он будет иметь ссылки на внешний класс, который обращается к пробелле).
Исправлено: избегайте использования нестатических внутренних классов в активности. Например, если мы объявляем обработчик статичным выше, его период выживания не имеет ничего общего с жизненным циклом деятельности. В то же время деятельность вводится с помощью слабых ссылок, чтобы избежать непосредственного передачи деятельности в качестве контекста. Смотрите следующий код:
Общедоступное пробоотключение класса Extances exation {/*** Статические внутренние классы не содержит неявную*ссылку на их внешний класс.*/Частный статический класс MyHandler расширяет handler {private final SleaseReference <SmappeActivity> Mactive; MSG) {SampleActivity Activity = mactivity.get (); if (activity! = null) {// ...}}} Приватный финал myhandler mhandler = new MyHandler (это);/*** Экземпляры анонимных классов не содержит неявную*ссылку на свой внешний класс, когда они «статичные». void run () {/ * ... */}};@переопределенный защищен void oncreate (bundle savedInstancestate) {super.oncreate (savedInStanceState); // опубликовать сообщение и задержать его исполнение в течение 10 минут.Обзор, рекомендуется использовать статический внутренний класс + SleaseReference. Будьте осторожны, чтобы быть пустым перед каждым использованием.
Shabreference упоминался ранее, поэтому я кратко расскажу о нескольких ссылочных типах объектов Java.
Java имеет четыре категории ссылок: сильная ссылка, Softreference, ShabReference и PhatomReference.
При разработке приложений Android, чтобы предотвратить переполнение памяти, при работе с некоторыми объектами, которые занимают большую память и имеют длинный цикл объявления, могут быть использованы мягкие ссылки и слабые эталонные технологии.
Мягкие/слабые ссылки могут использоваться в сочетании с эталонной очередью (reference quieue). Если объект, на который ссылается мягкая ссылка, переработана коллекционером мусора, виртуальная машина Java добавит мягкую ссылку на связанную справочную очередь. Эта очередь позволяет вам узнать переработанный список мягких/слабых ссылок, тем самым очищая буфер, который не выполнил мягкие/слабые ссылки.
Предположим, что наше приложение будет использовать большое количество изображений по умолчанию, такие как аватар по умолчанию, значок игры по умолчанию и т. Д., Которые будут использоваться во многих местах. Если вы читаете картинку каждый раз, оно будет медленнее, потому что чтение файла требует аппаратной работы, что приведет к снижению производительности. Поэтому мы рассмотрим кэширование изображения и читаем его непосредственно из памяти, когда это необходимо. Однако, поскольку изображения занимают много пространства памяти и кэша, многие изображения требуют большой памяти, исключения из перспективы могут быть с большей вероятностью. В настоящее время мы можем рассмотреть возможность использования мягких/слабых эталонных методов, чтобы избежать этой проблемы. Ниже приведен прототип кэша:
Сначала определите HashMap и сохраните мягкий эталонный объект.
Приватная карта <строка, softreference <bitmap >> ImageCache = new Hashmap <String, softreference <Bitmap >> ();
Давайте определим метод для сохранения мягкой ссылки растрового картера на HashMap.
После использования мягких ссылок, до того, как произошло исключение Outofmemory, пространство памяти этих кэшированных ресурсов изображения может быть освобождено, что предотвращает достижение памяти в верхнем пределе и избежав сбоя.
Если вы просто хотите избежать возникновения исключения Outofmemory, вы можете использовать мягкие ссылки. Если вы больше заботитесь о производительности вашего приложения и хотите перерабатывать некоторые объекты, которые занимают больше памяти как можно скорее, вы можете использовать слабые ссылки.
Кроме того, вы можете определить, часто используется ли объект для определения того, выбирается ли он для мягкой ссылки или слабой ссылки. Если объект можно использовать часто, попробуйте использовать мягкие ссылки. Если объект не используется более вероятно, его можно использовать со слабыми ссылками.
Хорошо, продолжай возвращаться к теме. Как упоминалось ранее, создайте статический внутренний класс обработчика и используйте слабые ссылки на объекты, удерживаемые обработчиком, так что объекты, удерживаемые обработчиком, также могут быть переработаны во время переработки. Однако, хотя это позволяет избежать утечки активности, в очереди сообщений все еще могут быть рассмотрены сообщения, поэтому мы должны удалить сообщения в Queue Queueue Message Queueue во время уничтожения или остановки действия.
Следующие методы могут удалить сообщение:
Public Final void RemoveCallbacks (Runnable R); Public Final void RemoveCallbacks (Runnable R, объект токена); Public Final void RemoveCallbacksandMessages (токен объекта); Public Final void elemlesEssess (int what); public final void elemlesEssess (int what, объект объекта);
Старайтесь избегать использования статических переменных элементов
Если переменная участника объявлена статичной, мы все знаем, что ее жизненный цикл будет таким же, как и весь жизненный цикл процесса приложения.
Это вызовет ряд проблем. Если процесс вашего приложения предназначен для резидента памяти, то даже если приложение переходит на фон, эта часть памяти не будет выпущена. В соответствии с текущим механизмом управления памятью мобильных приложений, фоновые процессы, которые учитывают большой объем памяти в первую очередь. Если это приложение обеспечило взаимную защиту процессов, оно приведет к тому, что приложение часто перезагружается в фоновом режиме. Когда телефон устанавливает приложение, которое вы участвовали в разработке, телефон потребляет питание и трафик в течение ночи, и ваше приложение должно быть удаленным или молчаливым пользователем.
Исправление здесь:
Не инициализируйте статические члены в начале класса. Ленивая инициализация может быть рассмотрена.
В архитектурном дизайне мы должны подумать о том, действительно ли необходимо сделать это и постараться избежать этого. Если архитектура должна быть разработана таким образом, вы несете ответственность за управление жизненным циклом этого объекта.
Избегайте переопределения завершения ()
1. Метод завершения выполняется в неопределенное время и не может быть положился на освобождение ограниченных ресурсов. Причины неопределенного времени:
Время, когда виртуальная машина вызывает GC, неясно
Время, когда запланировано поток Dainaze Date
2. Метод завершения будет выполнен только один раз. Даже если объект воскрешен, если метод завершения завершения выполнена, он не будет выполнен снова, когда он снова станет GC. Причина в:
Объект, содержащий метод завершения, генерирует ссылку на завершение виртуальной машиной, когда новая, и ссылается на объект. Когда метод завершения выполнения выполняется, будет выпущена ссылка на завершение, соответствующее объекту. Даже если объект воскрешен в это время (то есть ссылается на объект с сильной ссылкой), а второй раз, когда это GC, поскольку ссылка на завершение более не соответствует ему, метод завершения не будет выполнен.
3. Объект, содержащий метод завершения, должен пройти как минимум два раунда GC, прежде чем он может быть выпущен.
Утечка памяти, вызванная незаконным ресурсом
对于使用了BraodcastReceiver,ContentObserver,File,游标Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
一些不良代码造成的内存压力
有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。
например:
Bitmap 没调用recycle()方法,对于Bitmap 对象在不使用时,我们应该先调用recycle() 释放内存,然后才它设置为null. 因为加载Bitmap 对象的内存空间,一部分是java 的,一部分C 的(因为Bitmap 分配的底层是通过JNI 调用的)。 而这个recyle() 就是针对C 部分的内存释放。
构造Adapter 时,没有使用缓存的convertView ,每次都在创建新的converView。这里推荐使用ViewHolder。
Суммировать
对Activity 等组件的引用应该控制在Activity 的生命周期之内; 如果不能就考虑使用getApplicationContext 或者getApplication,以避免Activity 被外部长生命周期的对象引用而泄露。
尽量不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context ),即使要使用,也要考虑适时把外部成员变量置空;也可以在内部类中使用弱引用来引用外部类的变量。
对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以这样做避免内存泄漏:
将内部类改为静态内部类
静态内部类中使用弱引用来引用外部类的成员变量
Handler 的持有的引用对象最好使用弱引用,资源释放时也可以清空Handler 里面的消息。比如在Activity onStop 或者onDestroy 的时候,取消掉该Handler 对象的Message和Runnable.
在Java 的实现过程中,也要考虑其对象释放,最好的方法是在不使用某对象时,显式地将此对象赋值为null,比如使用完Bitmap 后先调用recycle(),再赋为null,清空对图片等资源有直接引用或者间接引用的数组(使用array.clear() ; array = null)等,最好遵循谁创建谁释放的原则。
正确关闭资源,对于使用了BraodcastReceiver,ContentObserver,File,游标Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销。
保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。
The above is a summary of the causes of memory leaks in Java introduced to you by the editor and how to avoid memory leaks (super detailed version). Я надеюсь, что это будет полезно для всех. If you have any questions, please leave me a message and the editor will reply to you in time. Большое спасибо за вашу поддержку сайту wulin.com!