Kotlin | Вопросы собесов
2.57K subscribers
28 photos
961 links
Download Telegram
🤔 Что знаешь о диспатчерах?

Диспетчеры в Kotlin определяют, на каком потоке будет выполняться корутина, например, Dispatchers.Main для UI-потока, Dispatchers.IO для ввода-вывода и Dispatchers.Default для фоновых вычислений. Они помогают распределять задачи по подходящим потокам, обеспечивая оптимальную производительность. Также можно создать собственный диспетчер для специфичных задач.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
🤔 Как можно получить сообщения на главном потоке с помощью Handler и Looper?

В Android для обработки сообщений и выполнения задач в основном (главном) потоке часто используются классы Handler и Looper. Handler позволяет отправлять и обрабатывать Message и Runnable объекты, ассоциированные с Looper. Главный поток приложения имеет свой Looper, который постоянно обрабатывает очередь сообщений и задач.

🚩Основные шаги для использования

1⃣Создание Handler
В главном потоке Handler можно создавать непосредственно, так как Looper уже существует. Это можно сделать в любом месте, например, в Activity или Fragment.
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

private Handler mainHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Создание Handler, привязанного к Looper главного потока
mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
// Обработка сообщений
if (msg.what == 1) {
// Пример обработки сообщения
String messageData = (String) msg.obj;
System.out.println("Received message: " + messageData);
}
}
};

// Пример отправки сообщения
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello from background thread!";
mainHandler.sendMessage(message);

// Пример отправки задачи
mainHandler.post(new Runnable() {
@Override
public void run() {
System.out.println("Runnable executed on main thread");
}
});
}
}


2⃣Отправка сообщений или задач на обработку в главный поток
Сообщения и задачи можно отправлять из любого потока. Например, из фонового потока:
new Thread(new Runnable() { 
@Override
public void run() {
// Отправка сообщения
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello from background thread!";
mainHandler.sendMessage(message);

// Отправка задачи
mainHandler.post(new Runnable() {
@Override
public void run() {
System.out.println("Runnable executed on main thread from background thread");
}
});
}
}).start();


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁1👀1
🤔 Фреймворк Dagger

Dagger — это фреймворк для внедрения зависимостей в Java и Kotlin. Он использует аннотации для описания зависимостей и автоматического их создания. Dagger генерирует код на этапе компиляции, который управляет зависимостями и предоставляет их нуждающимся классам. Он основан на принципах инверсии управления и часто используется для масштабируемых приложений, таких как Android-приложения. В Android Dagger помогает удобно управлять зависимостями, улучшая тестируемость и читаемость кода.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2🎉1
🤔 Как Looper связывается с потоком?

Looper и Handler являются основными компонентами для управления очередями сообщений в Android. Looper связывается с потоком, чтобы управлять очередью сообщений этого потока. Каждому потоку может быть назначен только один Looper, который обрабатывает сообщения и задачи, отправленные через Handler.

1⃣Создание Looper
По умолчанию главный поток приложения уже имеет Looper, и мы можем получить его с помощью Looper.getMainLooper(). Для других потоков мы должны создать Looper вручную.

2⃣Подготовка Looper для потока
Метод Looper.prepare() создает Looper для текущего потока. Метод Looper.loop() запускает цикл обработки сообщений для этого Looper.

3⃣Создание Handler, связанного с Looper
Handler использует Looper, чтобы определять, к какому потоку привязан, и куда отправлять сообщения и задачи.

🚩Пример создания Looper в новом потоке

1⃣Создание Looper и Handler в новом потоке
public class LooperThread extends Thread {
public Handler handler;
private Looper looper;

@Override
public void run() {
// Подготовка Looper для текущего потока
Looper.prepare();

// Создание Handler, связанного с этим Looper
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// Обработка сообщений
System.out.println("Received message: " + msg.what);
}
};

// Получение ссылки на Looper текущего потока
looper = Looper.myLooper();

// Запуск цикла обработки сообщений
Looper.loop();
}

// Метод для остановки Looper
public void quit() {
if (looper != null) {
looper.quit();
}
}
}


2⃣Использование LooperThread в Activity
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
private LooperThread looperThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Запуск LooperThread
looperThread = new LooperThread();
looperThread.start();

// Отправка сообщения в новый поток через Handler
findViewById(R.id.button_send_message).setOnClickListener(view -> {
if (looperThread.handler != null) {
Message message = Message.obtain();
message.what = 1;
looperThread.handler.sendMessage(message);
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// Остановка LooperThread
looperThread.quit();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Способы навигации в Kotlin

Jetpack Navigation Component — современный способ навигации, основанный на графе навигации и безопасных аргументах. Позволяет легко переходить между фрагментами и активностями, а также управлять состоянием навигации.
FragmentTransaction — ручной способ добавления, замены и удаления фрагментов.
Navigation через Intent — используется для переключения между активностями или фрагментами внутри приложения или между приложениями.
Explicit и Implicit Intents — явные и неявные намерения для навигации между компонентами.
NavHostFragment и NavController — связаны с использованием графа навигации для управления фрагментами в приложениях Android.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2
🤔 Как работает проверка на то, есть ли в потоке Looper?

Проверка на наличие Looper в потоке в Android осуществляется с помощью метода Looper.myLooper(). Метод Looper.myLooper()
public class LooperCheck {
public static void main(String[] args) {
// Проверка наличия Looper в главном потоке
if (Looper.myLooper() != null) {
System.out.println("Looper существует в текущем потоке.");
} else {
System.out.println("Looper не существует в текущем потоке.");
}

// Запуск нового потока без Looper
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// Проверка наличия Looper в новом потоке
if (Looper.myLooper() != null) {
System.out.println("Looper существует в новом потоке.");
} else {
System.out.println("Looper не существует в новом потоке.");
}

// Создание Looper в новом потоке
Looper.prepare();

// Проверка снова после создания Looper
if (Looper.myLooper() != null) {
System.out.println("Looper теперь существует в новом потоке.");
} else {
System.out.println("Looper все еще не существует в новом потоке.");
}

// Запуск цикла обработки сообщений
Looper.loop();
}
});

thread.start();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Data-классы в Kotlin

Data-классы в Kotlin — это классы, предназначенные для хранения данных. Они автоматически генерируют основные методы, такие как toString(), equals(), hashCode(), и copy(), упрощая работу с ними. Data-классы — это отличное решение, когда нужно хранить только данные, без логики, что делает код более чистым и понятным.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥1
🤔 Как бы сконфигурировал ThreadPool для библиотеки аналитики?

Когда поток в Android разбирает пустую очередь сообщений с помощью Looper.loop(), он будет заблокирован и останется в состоянии ожидания до тех пор, пока не появится новое сообщение или задача в очереди. Это нормальное поведение для потоков с Looper, которые предназначены для обработки сообщений и задач асинхронно.

🚩Поведение `Looper.loop()` при пустой очереди

1⃣Создание и запуск `Looper`
Когда Looper.loop() вызывается, поток начинает обрабатывать сообщения и задачи из очереди, связанной с Looper.

2⃣Обработка сообщений
Looper будет продолжать обрабатывать сообщения и задачи, пока они есть в очереди. Если очередь пуста, поток не завершает свою работу. Вместо этого он переходит в состояние ожидания и будет разбужен, когда появится новое сообщение или задача.

3⃣Блокировка потока
Если очередь пуста, Looper вызывает метод MessageQueue.next() для получения следующего сообщения. Этот метод блокируется до тех пор, пока новое сообщение не станет доступным. Это означает, что поток будет находиться в состоянии ожидания и не будет потреблять значительное количество ресурсов, пока не появится новое сообщение.

🚩Пример работы с `Looper` и пустой очередью
public class LooperThread extends Thread {
public Handler handler;

@Override
public void run() {
// Подготовка Looper для текущего потока
Looper.prepare();

// Создание Handler, связанного с этим Looper
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// Обработка сообщений
System.out.println("Received message: " + msg.what);
}
};

// Запуск цикла обработки сообщений
Looper.loop();
}
}

public class MainActivity extends AppCompatActivity {
private LooperThread looperThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Запуск LooperThread
looperThread = new LooperThread();
looperThread.start();

// Отправка сообщения в новый поток через Handler
findViewById(R.id.button_send_message).setOnClickListener(view -> {
if (looperThread.handler != null) {
Message message = Message.obtain();
message.what = 1;
looperThread.handler.sendMessage(message);
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// Остановка LooperThread
looperThread.handler.getLooper().quit();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Hilt для чего он используется?

Hilt — это библиотека для внедрения зависимостей в Android, построенная поверх Dagger. Она предоставляет простую настройку и интеграцию с Android-компонентами, такими как Activity, Fragment, ViewModel. Hilt автоматически управляет зависимостями и жизненным циклом компонентов, снижая сложность и уменьшая количество необходимого boilerplate-кода. Hilt особенно полезен для упрощения внедрения зависимостей в Android-приложениях.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
🤔 Как делегаты работают на уровне компиляции Java ?

Позволяют переопределять поведение свойств, делегируя его другим объектам с помощью ключевого слова by. На уровне компиляции Java компилятор Kotlin генерирует вспомогательные классы и методы доступа, которые используют делегаты.

🚩Пример делегата

import kotlin.properties.Delegates

class Example {
var p: String by Delegates.observable("<no name>") {
prop, old, new -> println("$old -> $new")
}
}

fun main() {
val e = Example()
e.p = "first"
e.p = "second"
}


🚩Как это работает на уровне компиляции?

1⃣Вспомогательные классы
Компилятор создает классы для управления состоянием делегированных свойств.
2⃣Методы доступа
Создаются геттеры и сеттеры, использующие вспомогательные классы.
3⃣Вызов делегата
Внутри методов доступа добавляются вызовы делегата для управления значениями.

public final class Example {
private final Delegates.Observable<String> p$delegate = Delegates.observable("<no name>", (property, oldValue, newValue) -> {
System.out.println(oldValue + " -> " + newValue);
return Unit.INSTANCE;
});

public final String getP() {
return this.p$delegate.getValue(this, Example.class.getDeclaredField("p"));
}

public final void setP(String value) {
this.p$delegate.setValue(this, Example.class.getDeclaredField("p"), value);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Для чего нужен let?

Функция let в Kotlin используется для работы с объектами в безопасном контексте. Это позволяет выполнять операции над объектами, если они не равны null. Она часто используется для работы с nullable типами, позволяя избежать явных проверок на null. Внутри блока let объект доступен через it, что позволяет элегантно обрабатывать его.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
🤔 Что быстрее, делегат или getter/setter ?

Когда речь идет о производительности, важно понимать, что делегаты и традиционные геттеры/сеттеры в Kotlin имеют разные цели и их производительность может зависеть от конкретного случая использования.

🚩Геттеры и сеттеры

Геттеры и сеттеры в Kotlin, как и в Java, это простые методы для получения и установки значений полей. Они имеют минимальный оверхед и выполняются очень быстро.
class Example {
var value: String = ""
get() = field
set(value) {
field = value
}
}


🚩Делегаты

Делегаты добавляют гибкость и позволяют переопределять поведение свойств. Однако эта гибкость имеет цену в виде дополнительного оверхеда, поскольку делегаты могут выполнять дополнительные действия (например, логирование, валидацию, уведомление об изменениях).
import kotlin.properties.Delegates

class Example {
var value: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}


🚩Сравнение производительности

🟠Геттеры и сеттеры
Минимальный оверхед, высокая производительность.
Ограниченная функциональность, жестко заданное поведение.
🟠Делегаты
Гибкость, возможность добавления дополнительной логики.
Больший оверхед из-за дополнительной логики и вызовов.

fun main() {
val exampleWithGetterSetter = ExampleGetterSetter()
val exampleWithDelegate = ExampleDelegate()

val iterations = 1_000_000

// Тест геттеров и сеттеров
var startTime = System.nanoTime()
for (i in 0 until iterations) {
exampleWithGetterSetter.value = "value"
val value = exampleWithGetterSetter.value
}
var endTime = System.nanoTime()
println("Getter/Setter time: ${(endTime - startTime) / 1_000_000} ms")

// Тест делегатов
startTime = System.nanoTime()
for (i in 0 until iterations) {
exampleWithDelegate.value = "value"
val value = exampleWithDelegate.value
}
endTime = System.nanoTime()
println("Delegate time: ${(endTime - startTime) / 1_000_000} ms")
}

class ExampleGetterSetter {
var value: String = ""
get() = field
set(value) {
field = value
}
}

class ExampleDelegate {
var value: String by Delegates.observable("<no name>") {
prop, old, new -> // Нет дополнительной логики для чистоты эксперимента
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Зачем нужен crossinline?

crossinline используется для предотвращения возврата из лямбда-функций, переданных в параметры функции. Это необходимо, если вы хотите, чтобы лямбда выполнялась без возможности "выхода" из текущего контекста, например, с помощью return. crossinline предотвращает такие ситуации, делая лямбду безопасной для вызова в асинхронных операциях или других специфичных контекстах.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
🤔 Как сконфигурировать ThreadPool, чтобы все отправлялось максимально быстро?

Чтобы настроить ThreadPool для максимальной скорости отправки данных в библиотеке аналитики, необходимо учитывать характер задач (например, это CPU-bound или I/O-bound задачи), объем данных и требования к производительности. Для большинства аналитических библиотек задачи отправки данных обычно связаны с I/O-bound задачами, так как они включают сетевые операции. Поэтому необходимо создать такой ThreadPool, который оптимально справится с высокими нагрузками и обеспечит быструю отправку данных.

🚩Конфигурация ThreadPool

1⃣Используйте CachedThreadPool
Подходит для большого количества кратковременных задач. Динамически создает новые потоки по мере необходимости и повторно использует существующие потоки.
2⃣Настройка размеров пула потоков
Для I/O-bound задач: размер пула потоков должен быть больше, чем количество ядер процессора, чтобы компенсировать задержки на I/O операции.

🚩Пример конфигурации ThreadPool

1⃣Использование CachedThreadPool
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

public class AnalyticsThreadPool {
private final ExecutorService executorService;

private static AnalyticsThreadPool instance;

private AnalyticsThreadPool() {
// Создание CachedThreadPool для динамического управления потоками
this.executorService = Executors.newCachedThreadPool();
}

public static synchronized AnalyticsThreadPool getInstance() {
if (instance == null) {
instance = new AnalyticsThreadPool();
}
return instance;
}

public void executeTask(Runnable task) {
executorService.execute(task);
}

public void shutdown() {
executorService.shutdown();
}
}


2⃣Использование Custom ThreadPoolExecutor
Если необходим более точный контроль над параметрами пула потоков, можно использовать ThreadPoolExecutor напрямую с кастомной конфигурацией:

🚩Пример использования AnalyticsThreadPool

public class AnalyticsLibrary {
private final AnalyticsThreadPool threadPool;

public AnalyticsLibrary() {
this.threadPool = AnalyticsThreadPool.getInstance();
}

public void logEvent(String event) {
Runnable task = new Runnable() {
@Override
public void run() {
// Выполнение аналитической задачи
sendEventToServer(event);
}
};
threadPool.executeTask(task);
}

private void sendEventToServer(String event) {
// Логика отправки события на сервер
System.out.println("Sending event: " + event);
// Здесь может быть код для отправки HTTP запроса
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Каким образом осуществляется навигация в Android?

Навигация в Android осуществляется несколькими способами, в зависимости от версии системы и используемых приложений. Основные методы включают жесты (свайпы, тапы), нажатия на экранные кнопки (на старых версиях), а также использование виртуальных или физических кнопок навигации (Домой, Назад, Последние приложения). Более современные версии Android полагаются преимущественно на жесты для навигации между приложениями и внутри них.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
🤔 Когда система понимает, что нужно освободить ядро и передать его кому-то другому?

Использует планировщик задач (scheduler) для управления использованием процессорных ядер различными потоками и процессами. Планировщик задач отвечает за распределение времени процессора между всеми активными задачами, обеспечивая многозадачность и эффективное использование ресурсов системы.

🚩Основные механизмы планирования задач

🟠Приоритеты задач
Задачи (процессы и потоки) могут иметь разные приоритеты. Более высокоприоритетные задачи получают больше времени на процессоре. В Android, каждый процесс и поток имеет уровень приоритета, который влияет на порядок выполнения.

🟠Временные квоты (time slices)
Временные квоты используются для распределения времени процессора между задачами. Когда задача использует свое выделенное время (time slice), планировщик может приостановить ее выполнение и переключиться на другую задачу.

🟠Состояние задачи
Задачи могут быть в разных состояниях: выполняются (running), готовые к выполнению (ready), ожидают (waiting) или заблокированы (blocked). Если задача переходит в состояние ожидания (например, ждет ввода/вывода), ядро освобождается и может быть передано другой задаче.

🚩Детали работы планировщика

🟠Приоритеты в Android
В Android приоритеты процессов управляются с помощью классов приоритетов (foreground, background, etc.). Foreground процессы (те, с которыми взаимодействует пользователь) имеют более высокий приоритет, чем background процессы.

🟠Временные квоты и контекстные переключения
Планировщик выделяет временные квоты задачам. После завершения квоты, если задача еще не завершена, планировщик приостанавливает ее и переключается на следующую задачу. Контекстные переключения происходят, когда планировщик сохраняет состояние текущей задачи и восстанавливает состояние следующей задачи.

🟠Блокировка задач
Если задача ожидает завершения операции ввода/вывода или другого события, она блокируется, и планировщик передает управление другому готовому к выполнению процессу.

🚩Пример ситуации

1⃣Выполнение Task A
Task A получает свое время на процессоре и начинает выполняться. Планировщик выделяет ей временную квоту (например, 50 миллисекунд).

2⃣Истечение времени Task A
Если Task A не завершена по истечении своей квоты, планировщик сохраняет ее состояние и переключается на другую задачу. Task B теперь получает управление и начинает выполняться.

3⃣Task A становится ожиданием
Если Task A выполняет операцию ввода/вывода и переходит в состояние ожидания, планировщик немедленно переключается на другую задачу, не дожидаясь окончания временной квоты.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Что такое лямбды с точки зрения синтаксиса в Java и Kotlin?

В Java лямбды — это упрощённый синтаксис для анонимных классов, реализующих функциональный интерфейс. Синтаксис: (параметры) -> { тело }. В Kotlin лямбды представляют собой выражения, передаваемые как функции, с синтаксисом { параметры -> тело }. Kotlin более лаконичен, позволяя опускать параметры, если их можно вывести из контекста.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3
🤔 Как LeakCanary понимает, что произошла утечка памяти?

Это мощный инструмент для обнаружения утечек памяти в Android-приложениях. Он работает, отслеживая жизненный цикл объектов и анализируя пути их удержания, чтобы определить, существуют ли объекты, которые не могут быть освобождены сборщиком мусора (Garbage Collector).

1⃣Интеграция с жизненным циклом компонентов
LeakCanary интегрируется с жизненным циклом Activity и Fragment с помощью своих наблюдателей (ActivityRefWatcher и FragmentRefWatcher). Эти наблюдатели отслеживают, когда Activity или Fragment был уничтожен и должен быть собран сборщиком мусора.

2⃣Создание слабых ссылок (WeakReference)
Когда Activity или Fragment должен быть уничтожен, LeakCanary создает слабую ссылку (WeakReference) на этот объект. Слабые ссылки позволяют сборщику мусора освободить объект, даже если на него есть слабые ссылки.
val weakReference = WeakReference(activity)


3⃣Ожидание сборки мусора (Garbage Collection)
LeakCanary инициирует сборку мусора и ждет, чтобы проверить, была ли освобождена слабая ссылка. Он вызывает метод System.gc() несколько раз, чтобы попытаться заставить сборщик мусора освободить память.
System.gc()


4⃣Проверка слабой ссылки
После вызова сборки мусора LeakCanary проверяет, является ли слабая ссылка null. Если слабая ссылка не равна null, это означает, что объект все еще удерживается в памяти и, вероятно, существует утечка памяти.
if (weakReference.get() != null) {
// Утечка памяти обнаружена
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👾1
🤔 Что такое dp?

dp (Density-independent Pixels) — это единица измерения в Android, используемая для создания адаптивных интерфейсов. Она масштабируется в зависимости от плотности экрана устройства, обеспечивая одинаковый визуальный размер элементов на разных экранах.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
🤔 Как понять, что в дампе есть утечка?

🚩Шаги анализа дампа памяти

1⃣Создание дампа памяти
Если объект не был освобожден после попыток вызвать сборку мусора, LeakCanary создает дамп памяти.

2⃣Анализ дампа
LeakCanary использует библиотеку Shark для анализа дампа памяти. Он проверяет все объекты в куче и их ссылки.

3⃣Проверка цепочки удержания
Shark проверяет, какие ссылки удерживают объект в памяти. Если объект должен был быть собран, но удерживается цепочкой ссылок, это указывает на утечку. Цепочка удержания показывает, какие объекты и ссылки не позволяют сборщику мусора освободить память.

🚩Пример цепочки удержания

1⃣Activity удерживается статическим полем
Например, если Activity удерживается статическим полем или через долгоживущий объект (например, Singleton), который не был правильно освобожден.

2⃣Анализ удерживающих ссылок
Shark анализирует пути от корневых объектов (root objects), таких как статические поля или глобальные переменные, к удерживаемому объекту.
RootObject -> Singleton -> Activity


Ставь
👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5