Серия Douyin по оптимизации производительности Android: Оптимизация памяти Java

Java Android

Как один из наиболее важных ресурсов для запуска компьютерных программ, память должна быть разумно выделена и переработана во время рабочего процесса.Необоснованное использование памяти приведет к тому, что пользовательское приложение будет работать с заиканием, ANR и черным экраном при свете, а пользовательское приложение будет в серьезных случаях.Происходит сбой OOM (недостаточно памяти). Будучи широко используемым продуктом, Douyin должен поддерживать отличную плавность и стабильность на различных машинных ресурсах.Оптимизация памяти — это звено, на которое следует обратить внимание.

Эта статья начинается с практики управления оптимизацией памяти Douyin Java OOM и пытается поделиться некоторыми мыслями команды Douyin об оптимизации памяти Java, включая создание инструментов и методологию оптимизации.

Предыстория Douyin Java OOM

Перед специальным управлением памяти Douyin мы разобрали абсолютное значение и относительный коллапс общих показателей памяти, и обнаружили, что пропорции очень высоки. Кроме того, во время Праздника Весны в прошлом году показатели, связанные с памятью, снова подскочили до рекордного уровня, так что в целом проблема с памятью достаточно серьезная и требует особого внимания. Douyin оптимизировал общую OOM Java на 80 % за счет предварительной атрибуции, создания инструментов и двухмесячного управления выделенной памятью.

Атрибуция верхнего стека Java OOM

До того, как управление оптимизацией памяти Java в Shake, мы сначала удалили текущую OOM в соответствии с стеком платформы, в основном разделенные на следующие категории:

Рисунок 1. Классификация OOM

вpthread_createНа долю проблемы приходится около 50% от общего числа, переполнение памяти кучи Java составляет более 40%, а остальное — небольшое количество переполнений fd. вpthread_createКак недостаточное количество fds, так и сбой уровня Java, вызванный ограничением собственной памяти.Мы также сделали целевые оптимизации для этой части проблемы с памятью, в том числе:

  • Схождение потоков, мониторинг
  • Автоматическое устранение утечки стека потоков
  • Мониторинг утечек FD
  • Мониторинг и оптимизация виртуальной памяти
  • Douyin 64-битный специальный

после управленияpthread_createПроблема была уменьшена до менее 0,02 ‰. Практика управления в этом отношении будет подробно представлена ​​​​в следующей практике управления памятью Douyin Native, так что следите за обновлениями. Эта статья посвящена управлению памятью кучи Java.

Идеи управления кучей памяти

Из классификации превышения лимита в стеке Java можно выделить два типа проблем:

1. Однократное выделение памяти кучи слишком велико, а накопление нескольких выделений слишком велико..

Причинами возникновения таких проблем являются исключения данных, которые приводят к тому, что одно выделение памяти становится слишком большим и превышает предел, а некоторые вызваны чрезмерным совокупным размером объединения StringBuilder и т. д. Решение этого типа проблем относительно простое, и проблема заключается в текущем стеке.

2. Кумулятивное распределение кучи памяти достигает вершины.

Стек задач такого типа будет разбросан, и он может сработать в любом сценарии выделения памяти, вероятность появления высокочастотных узлов выделения памяти будет выше, например, растровое выделение памяти. Основной причиной этого типа OOM является накопление чрезмерного использования памяти, а текущий стек — лишь последняя соломинка, сломавшая хребет верблюда, а не корень проблемы. Следовательно, для таких проблем нам необходимо проанализировать общую ситуацию с выделением памяти и найти неразумное использование памяти (например, утечки памяти, большие объекты, слишком много маленьких объектов, большие изображения и т. д.).

инструмент здание

Идеи инструментов

Если рабочий хочет хорошо работать, он должен сначала заточить свои инструменты. Исходя из приведенных выше идей по управлению памятью, основная проблема, которую должен решить инструмент, состоит в том, чтобы проанализировать общее распределение памяти и найти неразумное использование памяти (например, утечки памяти, большие объекты, слишком много маленьких объектов и т. д.).

Мы создаем инструменты из двух измерений, офлайн и онлайн:

не в сети

В первую очередь следует рассмотреть автономные инструменты, а утечки памяти можно обнаружить заранее во время разработки и тестирования. Такими же являются основные инструменты в отрасли, такие как Android Studio Memory Profiler, LeakCanary, Memory Analyzer (MAT).

На основе основной библиотеки LeakCanary мы разработали набор инструментов для автоматического анализа и сообщения об утечках памяти в автономном режиме.Основной процесс выглядит следующим образом:

Рисунок 2. Процесс автоматического автономного анализа

Запустив автономный инструмент для утечки памяти, Доуин обнаружил различные недостатки автономных инструментов:

  1. Выявлено слишком много утечек памяти, лучшей расстановки приоритетов нет, расхода на НИОКР не хватает, а исторические проблемы накапливаются. Кроме того, также трудно сообщить о преимуществах решения проблем с помощью бизнес-исследований и разработок. Всем сложно согласовать ROI (отношение ввода-вывода) для решения проблемы утечки памяти в автономном режиме.
  1. Автономные сценарии могут выполняться до ограниченного числа сценариев, и трудно исчерпать все пользовательские сценарии. У Douyin большая пользовательская база, и мы часто сталкиваемся с некоторыми проблемами онлайн-перегрузки OOM, которые невозможно проверить из-за отсутствия онлайн-данных.
  1. Приобретение HPORF на стороне Android зависит от родногоDebug.dumpHporf, процесс создания дампа приостанавливает основной поток и вызывает очевидную задержку, работа в автономном режиме неудовлетворительна, и часто возникают отзывы об исследованиях и разработках, которые влияют на тест.
  1. LeakCanary основан на анализе механизма анализа Shark, и скорость анализа относительно низкая.Обычно для завершения анализа требуется более 5 минут.Процесс анализа повлияет на использование памяти процессом.
  1. Результаты более одинокие, могут проанализировать только фрагмент, утечки памяти активности, как большой объект, слишком много проблем, вызванных небольшими объектами, нельзя проанализировать.

онлайн

Именно из-за некоторых из вышеуказанных недостатков о том, что самые ранние автономные инструменты Дуюна и процессы управления не играли большую роль. Мы должны были повторно изучить его, и в центре внимания конструкции инструмента сдвинулся от оффлайн в Интернете. Основная идея онлайн-инструмента: в условиях триггера, такими как OOM или PROFPIPAPE OOM или MEMORY, сбросьте файл HPROF в памяти, анализируйте файл HPROF, анализируйте утечки памяти, большие объекты, небольшие объекты и проблемы с изображениями, и следуют Утечка ссылки. Автоматическая атрибуция, сортировка больших проблем с данными в соответствии с количеством вхождения пользователей, размером утечки, общего размера и т. Д., И содействие исследованию бизнеса и разработки для установления процессов потребления в приоритетном порядке. С этой целью мы разработали набор автономных и онлайн-контурных автоматических инструментов анализа, на основе HPORF-анализа (отображение проблемы утечки памяти KO).

Представляем Лико

Общая архитектура Liko

Рисунок 3. Схема архитектуры Liko

Общая архитектура состоит из клиентского, сервера и базового анализа двух частей.

  • клиент

Полный сбор и анализ данных HPROF на стороне клиента (для режима анализа на устройстве), где онлайн- и офлайн-стратегии различаются.

онлайн: файл HPROF получается через незаметный дамп пользователя, в основном, когда OOM и память находятся наверху. Когда приложение выходит в фоновый режим и памяти достаточно, выполняется анализ. Чтобы уменьшить нагрузку на сервер, анализ на устройстве выполняется используется в качестве резервного для некоторой части пользователей.

не в сети: Конфигурация политики дампа является более агрессивной, инициируя дамп в различных сценариях, таких как OOM, пиковый объем памяти, скачок памяти, активность мониторинга и утечки фрагментов, достигающие определенного порога, а также анализирует и загружает его в фоновом режиме на терминале в режиме реального времени, и автоматически создает HTML-отчеты локально. Помогите R&D заранее обнаружить возможные проблемы с памятью.

  • Сторона сервера

The server side completes link aggregation, restoration, and allocation based on the big data returned online, and promotes R&D testing and consumption based on the number of user occurrences, leak size, and total size. For the backhaul analysis mode, HPORF analysis is additionally выполненный.

  • Анализировать двигатель

На основе механизма анализа MAT выполняется автоматическая атрибуция утечек памяти, крупных объектов, мелких объектов, изображений и т. д., а отчеты в формате Html автоматически генерируются в автономном режиме.

Блок-схема Лико

Рисунок 4. Блок-схема Liko

Общий процесс делится на

  1. Коллекция Hprof
  1. Время анализа
  1. Стратегия анализа

Коллекция Hprof

В процессе сбора мы установили множество стратегий, которые можно свободно комбинировать, в основном включая OOM, пиковую память, всплеск памяти, мониторинг активности и срабатывание, когда количество утечек фрагментов достигает определенного порога. разные.

Чтобы решить проблему зависания процесса дампа, мы используем метод подпроцесса dump+fileObsever для завершения сбора и мониторинга дампа.

перед разветвлением дочернего процессаSuspendПолучите копию потока в основном процессе, создайте дочерний процесс с помощью системного вызова fork и позвольте дочернему процессу иметь копию родительского процесса, а затем вызовите Hprof в дочернем процессе fork.DumpHeap函数即可完成把耗时的 dump 操作在放在子进程。 так какsuspendиresumeЭто системная функция, здесь мы используем собственный хук-инструмент собственной разработки, чтобыlibart.soловушка для получения системных вызовов. Поскольку запись завершается в дочернем процессе, мы отслеживаем время завершения дампа с помощью функции записи файла fileObsever, предоставляемой Android.

Рисунок 5. Блок-схема дампа подпроцесса

Время анализа Hprof

Чтобы гарантировать, что процесс анализа нечувствителен к пользователям, мы настроили различные стратегии синхронизации анализа в режиме онлайн и в автономном режиме.После завершения анализа дампа автономный анализ будет активно запускаться в соответствии с состоянием памяти.Онлайн, когда пользователь следующий холодный запуск и выход из приложения в фоновом режиме, а памяти достаточно, триггерный анализ.

Стратегия анализа

Мы предлагаем две стратегии анализа, одна для анализа на стороне клиента Android, а другая — для анализа на стороне сервера, обе из которых анализируются механизмом анализа MAT.

Анализ на устройстве
Механизм анализа

В конце концов производительность механизма анализа очень важна.Здесь мы в основном сравниваем механизм анализа Shark из LeakCanary и MAT библиотеки Haha.

Рисунок 6. Акула против MAT

Мы проанализировали и сравнили 160M HPROF несколько раз в одной и той же клиентской среде и обнаружили, что скорость анализа MAT значительно выше, чем у Shark.Кроме того, мы также активно освобождали память, занимаемую деревом линеек после анализа MAT. После сравнения преимуществ в производительности мы приняли метод на основе MAT.Аналитический механизм библиотеки анализирует, автоматически объединяет ссылки на утечки памяти, автоматически анализирует цепочки ссылок на большие объекты и маленькие объекты и автоматически восстанавливает большое изображение в автономном режиме. и фильтрует бесполезные ссылки онлайн.Результаты анализа следующие:

утечка памяти

Рисунок 7. Ссылка на утечку памяти

Цепочка ссылок утекшей активности агрегируется и анализируется, что удобно для одновременного решения утекшей цепочки активности и освобождения памяти.

большой объект

Рисунок 8. Ссылка на большой объект

Большие объекты не только анализируют ссылочные ссылки, но и рекурсивно анализируют внутренние верхние удерживающие объекты (InRefrenrece) из RetainedSize.

маленький объект

Рис. 9. Ссылка на малый объект

Маленькие объекты мы удерживаем внешние по отношению к вершине предметы (OutRefrenrece) агрегировать, чтобы получить связь с самыми мелкими объектами.

рисунок

Рисунок 10. Ссылка на изображение

Мы фильтруем галерею картинок и т. д. и недействительные ссылки на Android 8.0 под следующей большой картинкой онлайн были восстановлены.

Анализ вторичной переработки

Чтобы максимально сэкономить пользовательский трафик и избежать рисков для конфиденциальности, мы используем Tailor, инструмент обрезки HPROF собственной разработки, для обрезки HPROF в процессе создания дампа.

процесс резки

Рисунок 11. Процесс индивидуальной резки

Удалена бесполезная информация

  • пропустить заголовок
  • Вырезать по тегу

    • Обрезка мусора: char []; байт []; меттометр; серийный номер трассировки стека; серийный номер класса;
    • Сжатие данных

При этом выполняется сжатие данных zlib, а данные восстанавливаются на стороне сервера.Общий эффект обрезки: 180M--->50M---->13M

Практика оптимизации

утечка памяти

В дополнение к устранению наших общих утечек памяти путем автоматического распределения исследований и разработок и последующих действий на основе цепочки ссылок GCROOT+ в фоновом режиме, мы также проанализировали и устранили некоторые утечки памяти, вызванные системой.

Утечка системного асинхронного пользовательского интерфейса

Согласно цепочке ссылок агрегации загрузки, мы обнаружили, что ниже Android 6.0 есть HandlerThread, который содержит большое количество действий как GCROOT, что приводит к утечкам памяти.Согласно ссылке, обнаружено, что все эти утечка действий запускаемый Runnable (здесь Runnable — это системное событиеSendViewStateChangedAccessibilityEvent), эти Runnables добавляются в RunQueuel, который сам хранится в TheadLocal.

Рисунок 12. Ссылка утечки HandlerThread

мы начинаем сSendViewStateChangedAccessibilityEventНачал анализировать исходный код и обнаружил, что он вnotifyViewAccessibilityStateChangedIfNeededдобавлено, большое количество представлений системы будет в некоторых ее собственных методах пользовательского интерфейса (например:setChecked), чтобы активировать функцию изменения.

SendViewStateChangedAccessibilityEventизrunOrPostМетод перейдет к нашему обычно используемому представлениюpostDelayметод, этот метод будет добавлен в runQueue, если представление не было присоединено к корневому представлению.

Этот runQueue будет выполнен в следующий раз в основном потоке.performTraversals()потребляется в.

Если этот runQueue не находится в основном потоке, шансов на потребление нет.

В соответствии с приведенным выше анализом было обнаружено, что для возникновения такой утечки памяти необходимо выполнить некоторые условия:

  1. представление называетсяpostDelayметод (здесьnotifyViewAccessisbilityStateChangeIfNeededкурок)
  1. вид находится в отсоединенном состоянии
  1. Вышеупомянутый процесс выполняется в неосновном потоке, ThreadLocal не является UIThread, и runQueue, который он содержит, не будет запущен.performTraversalsпотреблять.

Douyin использует множество фреймворков асинхронного пользовательского интерфейса для оптимизации производительности рендеринга.Фрейворк управляется HandlerThread, который полностью соответствует вышеуказанным условиям. В ответ на эту проблему мы получаем ThreadLocal неосновного потока посредством отражения и активно очищаем внутреннюю RunQueue после каждого асинхронного рендеринга.

Рисунок 13. Процесс очистки отражения

Кроме того, Google исправил это на 6.0notifyViewAccessisbilityStateChangeIfNeededСуд не строгий.

утечки памяти

Большое количество утечек памяти, если мы полагаемся на исследования и разработки для решения, часто будет больше производства, чем потребления.Для этих неиспользованных утечек памяти мы отслеживаем и останавливаем потери на стороне клиента и добавляем активность onDestory вWeakRerefrence, отслеживайте, следует ли перезапускать после задержки в 60 секунд, и активно освобождайте фоновое изображение и изображение ImageView ViewTree, удерживаемое просочившейся активностью, если оно не перезапускается.

большой объект

В основном оптимизированы три типа крупных объектов.

  • Глобальный кеш: для глобального кеша мы освободили и понизили ненужные кеши по мере необходимости и попытались использовать слабые ссылки вместо сильных ссылочных отношений. большое количество утечек EventBus.
  • Системные большие объекты: Системные большие объекты, такие какPreloadDrawable,JarFileПутем анализа исходного кода мы определили, что активный выпуск не мешает исходной логике, а активный рефлекторный выпуск происходит, когда запуск завершен или когда память достигает верха.
  • Анимация: замена ресурсоемких кадровых анимаций собственными анимациями и устранение утечек анимации Lottie вручную.

Рисунок 14. Точка оптимизации большого объекта

маленький объект

Для оптимизации небольших объектов мы фокусируемся на трех измерениях: оптимизация полей, бизнес-оптимизация и оптимизация кеша.Разные измерения имеют разные стратегии оптимизации.

Рисунок 15. Идеи оптимизации малых объектов

Общая оптимизация класса

В бизнесе Douyin видео является самой основной и распространенной моделью. Хранилище данных бизнес-уровня Douyin разбросано по моделям, которые поддерживают свои собственные видео в каждом бизнесе. Сама модель объединяет множество атрибутов, необходимых для каждого бизнеса, в результате чего получается один экземпляр Использование памяти не является низким, и по мере того, как пользователь использует экземпляр процесса, использование памяти становится все больше и больше. Для самой модели мы можем оптимизировать две идеи оптимизации атрибутов и разделения.

  • Оптимизация поля: для поля одноразового атрибута, даже если кеш очищается после использования, например, внутри модели видео есть объект Json, после завершения десериализации объект Json не имеет значения использования и может быть очищен вовремя.
  • Разделение классов: для сложных бизнес-атрибутов общей модели попытайтесь управлять самой моделью, отсортируйте атрибуты, которые необходимо использовать для каждой бизнес-линии, и разделите модель на несколько бизнес-моделей и общую модель.Метод сводит к минимуму зависимость каждой бизнес-линии на своей собственной бизнес-модели и сокращает ненужную трату памяти на мешанину моделей.

Оптимизация бизнеса

  • Загрузка по запросу: мгновенные сообщения на Douyin будут сохранять сеансы глобально. При запуске приложения все сеансы будут загружены одновременно. Когда у пользователя слишком много сеансов, соответствующая глобальная память будет больше. Чтобы решить эту проблему, список сессий разбит на две Load, в память в первый раз загружается только определенное количество, а потом все подгружаются по необходимости.
  • Ограничение кэша памяти или очистка: каждая операция Loadmore в списке рекомендаций на главной странице не будет очищать ранее кэшированные видеообъекты, поэтому, когда пользователи остаются в ленте рекомендаций в течение длительного времени, слишком много кэшированных видеообъектов вызовут нехватку памяти. В случае экспериментальной проверки того, что это не окажет негативного влияния на бизнес, на кеш домашней страницы накладывается определенное количество ограничений для снижения нагрузки на память.

оптимизация кеша

Для модели видео, упомянутой выше, Доуин сначала использовал Manager для управления общими экземплярами видео. Диспетчер использует HashMap для хранения всех видеообъектов.В исходной схеме нет ограничений на размер памяти и логики очистки.По мере увеличения времени использования она продолжает расширяться, и в конечном итоге возникает исключение OOM. Для решения проблемы бесконечного расширения видеомодели разработан набор фреймворков кэширования, основной процесс выглядит следующим образом:

Рисунок 16. Фреймворк кэширования видео

Используйте механизм кэширования LRU для кэширования видеообъектов. Кэширует 100 последних использованных видеообъектов в памяти и кэширует видеообъекты на диск, когда они удаляются из кэша памяти. При получении видеообъекта он сначала берется из памяти, а если объект не закэширован в памяти, то из кеша диска. При выходе из приложения очистите кэш диска Менеджера, чтобы избежать увеличения использования дискового пространства.

рисунок

Что касается оптимизации изображений, мы в основном думаем об управлении библиотекой изображений и оптимизации самого изображения. В то же время использование необоснованных изображений также подвергалось проверке и мониторингу.

Галерея

Для библиотеки изображений устанавливается разумный кеш в соответствии с использованием изображений в приложении, и кеш изображений активно высвобождается, когда приложение или системная память ограничены.

оптимизация изображения

мы знаемФормула размера памяти изображения = разрешение изображения * размер каждого пикселя.

Разрешение изображения Мы уменьшаем ненужную трату пикселей, устанавливая разумную выборку.

//开启采样
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)
    .setDownsampleEnabled(true)
    .build();
Fresco.initialize(context, config);

//请求图片时,传入resize的大小,一般直接取View的宽高
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    .setResizeOptions(new ResizeOptions(50, 50))
    .build();mSimpleDraweeView.setController(
    Fresco.newDraweeControllerBuilder()
        .setOldController(mSimpleDraweeView.getController())
        .setImageRequest(request)
        .build());

Что касается размера одного пикселя, то заменой стандартного цветового канала системы drawable мы заменили некоторые форматы изображений без каналов прозрачности с ARGB_8888 на RGB565, потеря качества изображения практически незаметна невооруженным глазом, а память может быть непосредственно сохранены наполовину.

нижняя часть изображения

Для утечек изображений, вызванных активностью и утечками фрагментов, мыonDetachedFromWindowОтслеживается время и подводится итог, а конкретный процесс выглядит следующим образом:

Рис. 17. Итоговый процесс изображения

Мониторинг изображения

Что касается использования необоснованно больших изображений или изображений, мы перехватываем и отслеживаем их на уровне байт-кода, записываем информацию об изображении при создании собственного растрового изображения или библиотеки изображений и сообщаем о необоснованно больших изображениях; кроме того, в процессе настройки записей ImageView и отчеты также создаются для сценариев, в которых Bitmap намного превышает размер самого представления.

Рисунок 18. Схема мониторинга байт-кода изображения

больше думать

Закончится ли это, когда будет решена проблема с памятью OOM? Как команда, стремящаяся к максимуму, помимо решения проблемы использования статической памяти, мы также разработали инструмент Kenzo (Memory Insight), чтобы попытаться решить проблему зависания сборщика мусора, вызванного динамическим выделением памяти.

Принцип Кензо

Kenzo использует JVMTI для мониторинга памяти JVMTI (JVM Tool Interface) — это собственный программный интерфейс, предоставляемый виртуальной машиной Java. Во время разработки JVMTI приложение создает агент для использования JVMTI и может использовать функции JVMTI для установки функций обратного вызова, получения информации о текущем рабочем состоянии от виртуальной машины Java и принятия собственных бизнес-решений.

Рисунок 19. Диаграмма последовательности агентов

Jvmti SetEventCallbacksМетод может установить обратный вызов внутреннего события целевой виртуальной машины, который может быть основан наjvmtiCapabilitiesПоддерживаемые возможности и события, на которые мы ориентируемся, чтобы определить события, которые необходимо перехватить.

Kenzo использует Jvmti для выполнения следующих обратных вызовов событий:

  • Событие подготовки к загрузке класса -> Контролировать загрузку класса

    • ClassPrepare: фаза подготовки класса завершена.
  • GC -> Мониторинг событий и времени GC

    • GarbageCollectionStart: запуск сборщика мусора.
    • GarbageCollectionFinish: после завершения сборки мусора.
  • События объекта -> Отслеживание выделения памяти

    • ObjectFree: Когда GC освобождает объект.
    • VMObjectAlloc: Когда виртуальная машина выделяет объект.

каркасный дизайн

Kenzo целиком делится на две части:

производственная сторона

  • Собирать данные памяти
  • Интегрируйте в хост-приложение как SDK

потребитель

  • Данные процесса на стороне производства
  • Введите данные памяти, контролируемые Kenzo
  • вывод визуального отчета

ФИГ рама 20. Кензо

Рабочая сторона в основном использует Java для выполнения вызовов API, C++ завершает базовую логику обнаружения и завершает базовое логическое управление через JNI.

Сторона потребителя в основном использует Python для выполнения анализа данных и синтеза представлений, а также использует HTML для завершения отображения содержимого страницы.

Рабочий процесс

Рисунок 21. Фреймворк kenzo

Визуальный дисплей

Рисунок 22. Дисплей агрегата kenzo

Атрибуция памяти Startup

Основываясь на динамическом мониторинге памяти, мы выполнили атрибуционный анализ выделения памяти для большинства основных сценариев запуска и оптимизировали выделение узлов памяти для некоторых заголовков:

Рисунок 23. Атрибуция узла памяти при запуске

Кроме того, мы также обнаружили большое количество операций конкатенации строк на этапе запуска, хотя компилятор оптимизировал их в StringBuider.append, но глубокий анализ исходного кода StringBuider по-прежнему имеет большое количество действий динамического расширения (System.copy), чтобы оптимизировать потерю производительности динамического расширения, вызванного высокочастотными сценариями, в StringBuilderappend(), не переходите сразу кchar[]Добавляйте вещи, но сначала получите однуString[]Сохраните их и, наконец, поместите все длины строк, создайте StringBuilder разумной длины. Замените все StringBuilder, используя код байтового кода времени компиляции.appendМетод использует пользовательскую реализацию.После оптимизации FPS первой установки ленты домашней страницы и скольжения в течение 1 минуты увеличится на 1 кадр/с.Если он не установлен в первый раз, FPS скольжения в течение 1 минуты увеличится на 0,6 кадров/с.

Присоединяйтесь к нам

Мы являемся клиентской командой, отвечающей за исследование и развитие основных технических возможностей клиента Douyin и изучение передовых технологий.Мы сосредоточены на глубоком совершенствовании производительности, архитектуры, стабильности, инструментов исследований и разработок, компиляции и построения и т. д. , чтобы обеспечить эффективность исследований и разработок и инженерное качество сверхкрупномасштабной команды. , что делает Douyin, которым пользуются 600 миллионов человек, продуктом с максимальным удобством для пользователей.

Если вы увлечены технологиями, присоединяйтесь к команде разработчиков базовых технологий Douyin и позвольте нам создать глобальное приложение с миллиардным уровнем. В настоящее время у нас есть потребности в наборе персонала в Шанхае, Пекине, Ханчжоу и Шэньчжэне.Для внутреннего продвижения вы можете связаться с почтовым ящиком:tech@bytedance.com;заголовок письма:Имя - Годы работы - Douyin - Основные технологии - Android / iOS.

поделиться больше

Построение системы управления стабильностью видео «арбуз» 1: принцип адаптации и практика

Практика пополнения трехсторонней платежной системы на основе конечного автомата и очереди сообщений

UME — богатый инструмент отладки Flutter

Пример поиска и анализа ошибок оптимизации кода компилятора Go


Добро пожаловать в "Техническая команда ByteDance"

Контактный адрес электронной почты для доставки резюме "tech@bytedance.com"