WebView — это мощный компонент, позволяющий отображать веб-контент в вашем Android-приложении. Однако, поскольку это, по сути, полнофункциональный браузерный движок (Chromium), он потребляет значительное количество памяти и имеет сложную многопроцессную архитектуру.
Технические характеристики: Многопроцессная архитектура
На современных устройствах под управлением Android WebView использует многопроцессную модель для повышения безопасности и стабильности. Когда ваше приложение использует WebView, память распределяется между различными процессами:
- Процесс браузера (процесс приложения) : это основной процесс вашего приложения. Он содержит объект Java
WebViewи «браузерную» часть движка Chromium. Этот процесс управляет пользовательским интерфейсом, сетевыми запросами и рендерингом на графическом процессоре (интегрирован непосредственно с конвейером рендеринга Android HWUI). В отличие от Chrome, WebView не имеет отдельного процесса для графического процессора. - Процесс рендеринга : Этот процесс отвечает за анализ HTML, выполнение JavaScript и компоновку. Он изолирован от остальной части системы в целях безопасности. В настоящее время приложения используют только один процесс рендеринга для всех WebView (за исключением нескольких редких особых случаев), в отличие от Chrome, который часто использует отдельные процессы рендеринга для разных сайтов.

Почему это важно для памяти
При использовании dumpsys meminfo <your_package> вы видите только память, используемую процессом браузера (процессом вашего приложения). Память, используемая процессом рендеринга , учитывается отдельно.
Внутри браузерного процесса память WebView распределяется следующим образом:
- Java-куча : содержит Java-оболочку
WebViewи связанные с ней объекты. - Собственная куча : содержит внутренние структуры данных, кэши и состояние браузерного движка Chromium. Обратите внимание, что из-за использования PartitionAlloc некоторые собственные выделения памяти WebView могут не учитываться в разделе «Собственная куча» в
dumpsys meminfoи вместо этого отображаться в разделах «Другое» или «Неизвестно». - Разделяемая память : используется для совместного использования графических буферов и других данных. Эта информация может быть нечетко классифицирована командой
dumpsys meminfo.
Инструменты для устранения неполадок
Инструменты разработчика Chrome
Наиболее мощным инструментом для анализа памяти внутри WebView (процесса рендеринга) являются инструменты разработчика Chrome.
Включите отладку WebView в вашем приложении:
// NOTE: In production, this should be gated behind a developer setting // or only enabled for debuggable builds to prevent reverse engineering. WebView.setWebContentsDebuggingEnabled(true);Подключите устройство через USB.
Откройте Chrome на своем компьютере и перейдите по адресу
chrome://inspect/#devices.Найдите своё приложение и нажмите «Проверить код элемента» .
В окне «Инструменты разработчика» перейдите на вкладку «Память» , чтобы создавать снимки кучи или записывать временные шкалы выделения памяти для кучи JavaScript.
dumpsys meminfo
Используйте команду adb shell dumpsys meminfo --all <package> чтобы увидеть распределение памяти. Найдите в выводе категорию WebView и количество объектов.
Профилирование рендерера
Поскольку рендерер работает в отдельном процессе, вы не можете профилировать его собственную кучу, просто профилируя ваше приложение. Необходимо указать PID процесса рендерера.
Чтобы определить правильный PID рендерера при одновременной активности нескольких WebView:
Используйте
dumpsys activity:adb shell dumpsys activity processes <your_package_name>Найдите раздел
mConnections. Вы увидитеConnectionRecord, связывающий ваше приложение сSandboxedProcessService. PID этого процесса — это ваш рендерер. Пример:mConnections: - ConnectionRecord{... com.android.memorylab/org.chromium.content.app.SandboxedProcessService0:0 ...}Проверьте имена процессов : процессы рендеринга обычно называются
com.google.android.webview:sandboxed_processXили подобным образом. Если WebView используется только одним приложением, скорее всего, он будет только одним.
Получив PID, вы можете выполнить профилирование с помощью heapprofd .
Рекомендации по использованию памяти в WebView
Явное уничтожение
Предполагается, что приложения будут вызывать WebView.destroy() чтобы сообщить о завершении работы с экземпляром.
Хотя WebView пытается обеспечить автоматическую сборку мусора для каждого экземпляра и освобождение всех его ресурсов, гарантировать это на 100% сложно. Даже если автоматическая сборка мусора работает, она может значительно задерживаться, из-за чего приложение будет удерживать ресурсы гораздо дольше, чем ожидалось.
Если приложение вызывает WebView.destroy() в подходящий момент (например, в Activity.onDestroy() ), сохранение ссылки на сам объект WebView не приведет к утечке значительных нативных ресурсов. Нет необходимости обнулять ссылки на объект WebView в полях Activity после его уничтожения, поскольку они будут удалены сборщиком мусора при удалении самой Activity.
Упражнения: практическое применение памяти WebView.
Упражнение 1: анализ многопроцессного следа.
Запустите MemoryLab и выполните базовое измерение объема памяти, используемой вашим приложением:
adb shell dumpsys meminfo com.android.memorylabПример базового уровня (ранго):
TOTAL PSS: 18915 KBНажмите «Запустить WebView (обычный)» .
В WebView несколько раз нажмите кнопку «Выделить память JavaScript (1000 DIV)» .
Проверьте еще раз память приложения:
adb shell dumpsys meminfo com.android.memorylabОбратите внимание, что объем памяти в процессе вашего приложения не увеличивается значительно по сравнению с базовым уровнем! Это происходит потому, что элементы DOM находятся в процессе рендеринга .
Найдите процесс рендеринга:
adb shell ps -A | grep webview | grep sandboxedПример выходных данных:
u0_i9002 14227 1087 1632732 135880 do_epoll_wait 0 S com.google.android.webview:sandboxed_process0Проверьте объем памяти процесса рендеринга (используя его PID):
adb shell dumpsys meminfo 14227Обратите внимание на высокий общий размер PSS процесса рендеринга. В нашем тестовом запуске он подскочил до ~55 МБ после нескольких выделений памяти. Следует отметить, что выделения памяти JavaScript (обрабатываемые движком V8) обычно попадают в разделы Private Other или Unknown (mmap) файла
dumpsys meminfo, а не в кучу Dalvik.
Упражнение 2: утечка памяти в WebView на стороне Java.
Распространенная ошибка — это хранение экземпляра WebView в статическом поле или в долгоживущем объекте, что приводит к утечке памяти. Поскольку объект WebView является «тяжеловесным якорем», который удерживает собственные ресурсы и потенциально целые процессы рендеринга, его утечка памяти обходится очень дорого.

- В MemoryLab нажмите «Запустить WebView (утечка Java)» .
- Активность автоматически закроется после загрузки страницы (имитируя многократную навигацию и накопление утечек).
- Нажмите кнопку 4 раза.
Проверьте количество экземпляров
WebViewв вашем приложении:adb shell dumpsys meminfo com.android.memorylabВнизу страницы найдите раздел «Объекты» . Вы увидите, что количество
WebViewsувеличилось до 4.Пример выходных данных (4 случая утечки) в Rango:
Objects Views: 51 ViewRootImpl: 5 AppContexts: 14 Activities: 5 Assets: 38 AssetManagers: 0 Local Binders: 55 Proxy Binders: 77 Parcel memory: 41 Parcel count: 68 Death Recipients: 3 WebViews: 4Сделайте дамп кучи и используйте AHAT для поиска утечки. Если
ahatотсутствует в вашем пути, вы можете собрать его из дерева Android:# Dump heap from device adb shell am dumpheap com.android.memorylab /data/local/tmp/heap.hprof adb pull /data/local/tmp/heap.hprof # Run ahat using the built JAR (found in out/host/linux-x86/framework/) java -jar out/host/linux-x86/framework/ahat.jar -p 8888 heap.hprofВ веб-интерфейсе AHAT (
localhost:8888) нажмите на ссылку «Выделение памяти» (или «Сайты ») в верхнем меню, чтобы увидеть общее использование памяти.
Найдите класс
android.webkit.WebView. Щелкните по количеству его экземпляров , чтобы увидеть все активные экземпляры. В списке должно быть несколько экземпляров.
Щёлкните по одному из утёкших экземпляров
WebView. Прокрутите вниз до раздела «Sample Path from GC Root» . Вы увидите, что он хранится в спискеsLeakedWebViewsвcom.android.memorylab.WebViewActivity.
← Нативный | ↑ Вверх | Код приложения →