В процессе переделок заметил что производительность моего рантайм приложения существенно понизилась, и как показывает сравнительный анализ с предыдущими версиями, во многом из за существенно возросшего числа вызовов GC_CONCURRENT останавливающего приложение на 50-100 мс что чрезвычайно разрушительно для рантайма. Погрешив на увеличение количества потоков я переписал приложение так что бы оно все делало в основном потоке, однако, количество вызовов GC_CONCURRENT это не уменьшило ни сколько.
Отсюда вопрос: о какой конкуренции идет речь?
Пока на уме только копирование заимствованного из других классов кода, что избежать ни как не получится
Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
- Mikhail_dev
- Сообщения: 2386
- Зарегистрирован: 09 янв 2012, 14:45
- Откуда: Самара
Re: Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
Почитайте данную статью - http://habrahabr.ru/post/222199/ , особенно Allocation tracker и Method profiling. В первом вы найдете такую информацию, как какие объекты создаются часто (ведь GC их и чистит), а во втором можете посмотреть какие места программы у вас самые нагруженные.
Хех, не стоило этого делать. В таких ситуациях легче знать, а не думать.Погрешив на увеличение количества потоков я переписал приложение
Re: Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
Когда -то давно подобная тема подымалась, потому просто оставлю цитату одного ответа:
Что же, проблема решилась. С памятью и количеством объектов на java это оказалось никак не связано.
Тормозил вовсе не GC_CONCURRENT. В глубине далвика есть такая функция - gcDaemonThread. Это демон сборщика мусора. Как гласит её описание, она инициирует GC_CONCURRENT по внешнему сигналу. Так же через несколько секунд после этого она обрезает кучу. Из-за бага ( https://code.google.com/p/android/issue ... l?id=26627 ) (который есть по меньшей мере в 4.0.3) обрезка кучи происходила не через несколько секунд, а ровно через 5 мсек после сборки мусора. Т.е. визуально дерганье происходило ровно в момент появления в логах сообщения о работе сборщика. Поэтому сразу начали грешить на невиновный, как оказалось, GC_CONCURRENT.
Функция обрезки кучи trimHeaps() сканирует память процесса на предмет свободных страниц памяти, и когда находит, вызывает системную функцию madvise(..., MADV_DONTNEED). Всё бы ничего, но на время работы этой функции лочится далвиковская куча. Т.е. если вдруг в этот момент в java вызывается new, то он послушно ждет, пока trimHeaps() закончит. В особо тяжелых случаях время её работы у меня достигало 300-400 мсек. Для игры такая пауза определенно бросалась в глаза.
Внутри функции trimHeaps() вызывалась функция dlmalloc_walk_free_pages(). Именно она из 300 мсек работала 290. От чего зависит время её работы? От количества объектов, созданных в нативном коде(имеется ввиду код на С++, скомпилированный с помощю ndk). Конкретно в моем случае плодило в больших количествах объекты бинарное дерево. В некоторых ситуациях количество нод - отдельно созданных объектов - достигало 100к и больше. И хотя одна нода занимала всего 16 байт, а всё дерево чуть больше полутора мегабайт, количество произведенных аллокаций катастрофическим образом сказывалось на времени работы dlmalloc_walk_free_pages().
Как решение проблемы, написал промежуточный аллокатор, который обслуживает бинарное дерево. В результате количество прямых dlmalloc уменьшилось на 3 порядка. dlmalloc_walk_free_pages() теперь не привлекает внимания. Все рады.
Вывод:
Количество аллокаций в нативном коде может серьезно затормозить аллокации на java-стороне, хотя раньше я думал что в нативном коде могу творить что хочу. Будьте осторожны.
- Mikhail_dev
- Сообщения: 2386
- Зарегистрирован: 09 янв 2012, 14:45
- Откуда: Самара
Re: Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
Хм, интересная заметка.
Но это можно легко проверить. Достаточно лишь проанализировать тулзой "Method profiling' кто и как долго поедает. Если это будет GC, то будет большой процент его работы.
Но это можно легко проверить. Достаточно лишь проанализировать тулзой "Method profiling' кто и как долго поедает. Если это будет GC, то будет большой процент его работы.
Re: Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
Тоже натыкался на эту статью когда пытался загуглить вопрос, но очевидно что к падению производительности имели именно мои действия.altwin писал(а):Когда -то давно подобная тема подымалась, потому просто оставлю цитату одного ответа:
Как показал анализ DDMS проблема скрылась в инициализации такой простой вещи как вектор (двухколесный), и алгоритма работающего на большом числе операций с векторами, среди которых встречается умножение на число, возвращающее новый вектор. Это было не страшно до того момента как я расширил вектор внеся в него список линкованных данных, и с тех пор цена создания вектора существенно возросла. Нынешнее состояние жрет 13% процессорного времени только на создание этих самых векторовMikhail_dev писал(а):Почитайте данную статью - http://habrahabr.ru/post/222199/ , особенно Allocation tracker и Method profiling. В первом вы найдете такую информацию, как какие объекты создаются часто (ведь GC их и чистит), а во втором можете посмотреть какие места программы у вас самые нагруженные.
Цитата:
Погрешив на увеличение количества потоков я переписал приложение
Хех, не стоило этого делать. В таких ситуациях легче знать, а не думать.
- Mikhail_dev
- Сообщения: 2386
- Зарегистрирован: 09 янв 2012, 14:45
- Откуда: Самара
Re: Конкуренция в гарбэдж коллекторе (GC_CONCURRENNT)
Ну это понятно. Просто так можно "в лоб" найти узкие места производительности.но очевидно что к падению производительности имели именно мои действия.