Форум программистов, компьютерный форум, киберфорум
Наши страницы
Программирование Android
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/13: Рейтинг темы: голосов - 13, средняя оценка - 5.00
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
1

Оптимизация приложения. Слишком часто вызывается GC

16.07.2013, 15:30. Просмотров 2320. Ответов 28
Метки нет (Все метки)

Требуются некоторые разъяснения по работе GC и некоторая помощь в оптимизации.

Есть два проблемных места, в обоих очень часто создаются модели JSON.

Дело в том что постоянно через WebSocket идет непрерывный поток примерно 10Кб\с. Для каждого сообщения создается JSON, парсится, обрабатывается и когда приходит следующее сообщение старый JSON теряет ссылку и подбирается GC (мне кажется что всё происходит именно так).

В результате на момент работы GC приложение приостанавливается и появляются задержки.
Меня интересует, правда ли что GC_CONCURRENT полностью блокирует приложение на время своей работы (хотя он должен работать синхронно с приложением). По логам видно, что утечек памяти нет, но вызовы GC очень частые, иногда чаще чем раз в 10 секунд.

07-16 14:21:38.403: D/dalvikvm(16883): GC_CONCURRENT freed 1427K, 23% free 13244K/17112K, paused 105ms+7ms, total 168ms
07-16 14:21:43.578: D/dalvikvm(16883): GC_CONCURRENT freed 1807K, 22% free 13483K/17112K, paused 10ms+24ms, total 162ms
07-16 14:21:51.842: D/dalvikvm(16883): GC_CONCURRENT freed 1890K, 21% free 13539K/17112K, paused 59ms+19ms, total 156ms
07-16 14:22:02.282: D/dalvikvm(16883): GC_CONCURRENT freed 1941K, 21% free 13551K/17112K, paused 19ms+16ms, total 138ms
07-16 14:22:06.276: D/dalvikvm(16883): GC_CONCURRENT freed 2001K, 22% free 13500K/17112K, paused 6ms+4ms, total 91ms
07-16 14:22:17.287: D/dalvikvm(16883): GC_CONCURRENT freed 1878K, 21% free 13561K/17112K, paused 12ms+6ms, total 97ms
07-16 14:22:28.138: D/dalvikvm(16883): GC_CONCURRENT freed 1936K, 21% free 13562K/17112K, paused 6ms+20ms, total 104ms
07-16 14:22:35.194: D/dalvikvm(16883): GC_CONCURRENT freed 1926K, 21% free 13557K/17112K, paused 3ms+11ms, total 64ms
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.07.2013, 15:30
Ответы с готовыми решениями:

Не вызывается onDestroy при принудительно остановке приложения
Есть приложение с использованием нативной библиотеки. В onCreate вызывается...

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

Оптимизация приложения
Дорогие форумчане!Работаю над приложение. Его смысл в том что бы заполнять...

Оптимизация приложения
Здравствуйте, уважаемые форумчане, подскажите пожалуйста в трех вопросах. ...

C# оптимизация приложения под разные экраны(не GUI)
Здравствуйте. Дело в том, что изначально я делал игру(2d в Unity через...

28
Wenceslaus
Android Developer
130 / 130 / 6
Регистрация: 05.07.2013
Сообщений: 205
16.07.2013, 15:56 2
Да, при каждом создании модели/объекта JSON выделяется память, когда её начинает не хватать, то вызывается GC и блокирует все потоки в приложении (порядка 200мс). При чём, если я не ошибаюсь, под приложение выделяется что-то около 10мб памяти. Так что в вашем случае я бы смотрел на оптимизацию создания/парсинга JSON модели.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
16.07.2013, 16:02  [ТС] 3
Хотелось бы найти альтернативу. Возможно ли как-то переиспользовать JSON объекты по несколько раз, что бы они не очищались мусорщиком? Я не нашел возможности заменить String готового объекта JSON, что бы он после этого заново её распарсил, кроме создания нового объекта.
Может есть библиотека с другим парсером позволяющая подобное?
0
Wenceslaus
Android Developer
130 / 130 / 6
Регистрация: 05.07.2013
Сообщений: 205
16.07.2013, 16:20 4
А вы пользуетесь GSON'ом? Если так, то jackson быстрее будет. Но насколько это решит проблему с GC я не знаю.
Может быть я что-то подскажу, если увижу код получения/парсинга JSON'а, но не факт..
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
16.07.2013, 16:24  [ТС] 5
В данном случае используется обычный парсер Android, и т.к. парсинг выполняется в другом потоке проблем с задержками из-за этого не возникает.

Java
1
2
3
4
5
6
7
8
9
10
11
12
    @Override
    public void onMessage(String message) {
        try {
            jsonArray = new JSONArray(message);
            int lenght = jsonArray.length();
            for (int i = 0; i < lenght; i++) {
                model = new TickerInstrumentModel(jsonArray.getJSONObject(i).toString());
                tickerContent.updateContent(model);
            }
        } catch (Exception e) {
        }
    }

В этот метод приходит по несколько сообщений в секунду. В результате я получаю модель, которую складываю в Map, а когда данные обновились просто заменяю на новую. И т.к. обновляется она очень часто, около 50 моделей за одну секунду, то они очищаются
0
Wenceslaus
Android Developer
130 / 130 / 6
Регистрация: 05.07.2013
Сообщений: 205
16.07.2013, 18:07 6
О jackson'е я только слышал, а вот GSON использую часто. Так вот фича в том, что GSON не создаёт промежуточные объекты и парсит строку уже в готовую модель, не могу сказать, что это полностью решит проблему, но по крайней мере уменьшит количество создаваемых объектов и преобразований.. Попробуйте..
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:07 7
у меня GC никогда не вызывал никаких задержек.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:09  [ТС] 8
Цитата Сообщение от MonStar Посмотреть сообщение
paused 105ms+7ms
В любых источниках описано, что это означает, что в начале свой работы GC останавливает приложение на 105ms, а под конец на 7ms. Это и вызывает подвисания
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:12 9
имел ввиду на практике никогда GC не был причиной тормозов в приложении.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:16  [ТС] 10
Цитата Сообщение от V0v1k Посмотреть сообщение
имел ввиду на практике никогда GC не был причиной тормозов в приложении.
Не уверен, что кто-то вообще знает, в какой момент времени вызывается GC, ибо он совершенно непредсказуем. Но в моем приложении, как видно по логам вызывается часто. И предположение почему это происходит я тоже пытался описать. Вот только не знаю как с ним бороться
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:26 11
вроде до 200мс не должно быть заметно для пользователя.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:28  [ТС] 12
Вот маленький сэмпл. По таймеру создается около 50 объектов в секунду. И переодически в логе можно увидеть как вызывается GC.
В моем приложении такая же ситуация, вот только размеры объектов и количество может быть гораздо больше. А вместо String у меня JSON

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainActivity extends Activity {
 
    private TextView textView;
    private int count = 0;
    private Handler handler;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.text);
        Timer timer = new Timer();
        handler = new Handler();
        TimerTask task = new TimerTask() {
            
            @Override
            public void run() {
                handler.post(new Runnable() {
                    
                    @Override
                    public void run() {
                        textView.setText("COUNT : " + count++);
                        String s = new String();
                    }
                });
            }
        };
        timer.schedule(task, 20, 20);
    }
}
Добавлено через 1 минуту
Цитата Сообщение от V0v1k Посмотреть сообщение
вроде до 200мс не должно быть заметно для пользователя.
Как я уже писал, для меня критично даже 10ms. Т.к. идет бегущая строка, которая не должна подрагивать из-за таких мелких вызовов. А они очень частые и легко достигают 50ms
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:34 13
ну так я и говорю, не должно быть заметно никаких подрагивань если задержка меньше 200мс.

Добавлено через 28 секунд
или вы думаете что это строка обновляется каждые 10мс?

Добавлено через 3 минуты
Цитата Сообщение от MonStar Посмотреть сообщение
По таймеру создается около 50 объектов в секунду. И переодически в логе можно увидеть как вызывается GC.
В моем приложении такая же ситуация, вот только размеры объектов и количество может быть гораздо больше.
и зачем же столько объектов плодить?
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:36  [ТС] 14
Цитата Сообщение от V0v1k Посмотреть сообщение
ну так я и говорю, не должно быть заметно никаких подрагивань если задержка меньше 200мс.
Тем не менее подрагивания есть и они заметны.

Цитата Сообщение от V0v1k Посмотреть сообщение
или вы думаете что это строка обновляется каждые 10мс?
Каждую секунду мне приходит около 10кб данных. Мне нужно создать JSON объект, распарсить его, сложить все данные, а уже через несколько секунд, если оне не нужны заменить их такими же, но уже свежими. Так вот с таким большим потоком данных все неиспользованные объекты убирает GC. В итоге я получаю то что получаю - задержки в приложении. В секунду получается не менее 50 JSON объектов

Добавлено через 1 минуту
Цитата Сообщение от V0v1k Посмотреть сообщение
и зачем же столько объектов плодить?
Я вынужден хранить всё, что бы в нужный момент отобразить, а не ждать когда мне снова они придут
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:39 15
может храните в нераспарсеном виде и парсьте когда нужно отобразить...

еще покажите что делает updateContent, может кто подскажет как оптимизировать чтобы меньше объектов плодилось.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:44  [ТС] 16
Цитата Сообщение от V0v1k Посмотреть сообщение
может храните в нераспарсеном виде и парсьте когда нужно отобразить...
Не думаю что подойдет, данные приходят в виде JsonArray, при чем если один раз придет [a,b,d], то второй раз может прийти [b,d,c], а третий [a,d,c].
Да и стринги тоже объекты, они тоже будут очищаться
Цитата Сообщение от V0v1k Посмотреть сообщение
еще покажите что делает updateContent, может кто подскажет как оптимизировать чтобы меньше объектов плодилось
Он просто складывает распарсеные данные в Map и достает их, когда нужно отобразить на экран. В результате всегда имеем 100% свежие данные
Java
1
2
3
4
5
6
    public void updateContent(TickerInstrumentModel model) {
        String instrument = model.getInstrument();
        if (isNeeded(instrument)) {
            models.put(instrument, model);
        }
    }
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 00:48 17
не понял почему бы просто не хранить последний JsonArray, а когда нужно будет отобразить, тогда и парсить.
или даже не JsonArray, а просто String c всем джейсоном.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 00:51  [ТС] 18
Цитата Сообщение от V0v1k Посмотреть сообщение
не понял почему бы просто не хранить последний JsonArray, а когда нужно будет отобразить, тогда и парсить.
или даже не JsonArray, а просто String c всем джейсоном.
Я думал, что ответил на этот вопрос в предыдущем сообщении
JsonArray содержит данные вразнобой. Если у меня например 10 видов данных, то в одном массиве может прийти 1,2,5 а в другом 7,8,10. А какой из них мне нужно решаю уже внутри приложения. Следовательно нужно парсить, что бы посмотреть что внутри

String хранить не вижу смысла по той причине, что он в конце концов тоже будет очищаться и забираться GC, по сути тоже самое, только объект поменьше
0
V0v1k
1160 / 984 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
17.07.2013, 01:01 19
Цитата Сообщение от MonStar Посмотреть сообщение
String хранить не вижу смысла по той причине, что он в конце концов тоже будет очищаться и забираться GC, по сути тоже самое, только объект поменьше
ну, 1 объект лучше чем 100.
Цитата Сообщение от MonStar Посмотреть сообщение
JsonArray содержит данные вразнобой. Если у меня например 10 видов данных, то в одном массиве может прийти 1,2,5 а в другом 7,8,10. А какой из них мне нужно решаю уже внутри приложения. Следовательно нужно парсить, что бы посмотреть что внутри
ну так храните 10 объектов, вам же не нужно полностью пропарсить объект чтобы узнать его тип?
так где конкретно парсинг происходит покажите?

Добавлено через 2 минуты
а то написали в теме "Оптимизация приложения", а код этого приложения не показываете.
друдно что-то советовать если не видно полной картины.
0
MonStar
22 / 22 / 4
Регистрация: 10.04.2011
Сообщений: 241
17.07.2013, 01:13  [ТС] 20
Цитата Сообщение от V0v1k Посмотреть сообщение
а то написали в теме "Оптимизация приложения", а код этого приложения не показываете.
друдно что-то советовать если не видно полной картины.
Сомневаюсь, что поможет лишняя сотня классов, которая затрагивает другие части приложения. По возможности могу показать, что где происходит конечно.

Метод ниже подключается к непрерывному потоку WebSocket'а и постоянно получает строки в виде JsonArray
Java
1
2
3
4
5
6
7
8
9
10
11
public void onMessage(String message) {
        try {
            jsonArray = new JSONArray(message);
            int lenght = jsonArray.length();
            for (int i = 0; i < lenght; i++) {
                model = new TickerInstrumentModel(jsonArray.getJSONObject(i));
                tickerContent.updateContent(model);
            }
        } catch (Exception e) {
        }
    }
Сначала парсится весь Array, а потом каждый объект в отдельности. Как я сказал по задумке встроенного JSON в Android это происходит в момент создания объекта. TickerInstrumentModel - это наследник JsonObject.

Потом модель передается в управление контентом, где метод isNeeded(instrument) решает, нужно нам это или нет. Если нет то он просто отпадает, если да, то сохраняется в Map. В итоге Map хранит 50 различных объектов (ключ всегда одинаковый), но с разными данными.
Java
1
2
3
4
5
6
7
8
9
    
private Map<String, TickerInstrumentModel> models;
 
public void updateContent(TickerInstrumentModel model) {
        String instrument = model.getInstrument();
        if (isNeeded(instrument)) {
            models.put(instrument, model);
        }
    }

Затем в момент, когда потребовалось получить все данные (предыдущие закончились) вызывается такой метод
Java
1
2
3
    public void requestContent(final IContentBuildCallback callback) {
        contentBuilder.build(models, settings, callback);
    }
Он отдает Map наверх в UI и я его отображаю в виде бегущей строки.

Добавлено через 1 минуту
Цитата Сообщение от V0v1k Посмотреть сообщение
ну так храните 10 объектов, вам же не нужно полностью пропарсить объект чтобы узнать его тип?
Нужно полностью парсить обязательно, иначе не узнать что внутри


Пока писал, что-то упустил. JSON парсится в момент создания объекта на сколько я знаю. Это
Java
1
new JSONArray(message);
и
Java
1
new TickerInstrumentModel(jsonArray.getJSONObject(i));
0
17.07.2013, 01:13
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.07.2013, 01:13

Индекс вида "бьется" слишком часто
В общем не знаю в какой раздел писать Толи администрирование то ли...

Windows 8.1. Слишком часто выдает синий экран
Доброго времени суток, форумчане! Я в отчаянии. Помогите пожалуйста...

QGraphicsView слишком часто отрисовывает сцену = тормоза
Не могу сообразить, как сделать так, чтобы сцена (модель) рассчитывалась часто,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru