Показать сообщение отдельно
Старый 18.12.2014, 06:56   #16
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Смесь: Неочевидное + Оптимизация

Загрузка советов - "лишние" 400 кб RAM

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

В данный момент советов много, суммарное количество символов текста около 5900. т.е. примерно 5900*4 = 23,6 кб.

Есть версионность, т.е. советы присылаются из сокета только если в клиенте устаревшая версия. Иначе достаём из кэша.

Выяснил вот что.
1. До загрузки советов занято 1130 кб оперативки
2. Каждый совет в среднем жрёт 1-2 кб
3. На момент загрузки всех советов из сокета занято 1205 кб
4. После завершения функции tipsPrepare() занято 1548 кб
5. После очередного вызова сборщика мусора занято 1110 кб

Принцип добавления советов
1. Каждый совет присылается в отдельной команде
2. При получении команды добавляем совет в список (LinkedList)
3. Добавляем все советы
4. Создаём строковый массив tips, из которого будем рандомно выцеплять совет для показа
5. В цикле проходим по списку с советами, заполняя массив и формируя длинную строку, содержащую все советы, чтобы далее сохранить эту строку в кэш (внутр. память)
6. чистим список советов (хотя это особо ничего не даёт, т.к. ссылки на строки есть в массиве)

Самое прожорливое место - формирование строки для сохранения в кэш. Опять это "дурацкое" пересоздание массива chars внутри StringBuffer'a при сложении строк.
tipsString "";
for(
listTips.start(); listTips.hasElement(); listTips.next(), ++k) {
    
tips[k] = (String)listTips.item();
    if(
tipsString.length() > 0)
        
tipsString += "\r\n";
    
tipsString += tips[k];

После этого цикла оперативка доходит до 1496 кб.

Далее идёт сохранение в кэш, которое и доводит до финального уровня 1548 кб.

Решение, оптимизация

Сделал переменную int tipsStrLen, в которую плюсую длину каждого совета при его добавлении в список, и юзаю StringBuffer заранее указанной длины:
StringBuffer buf = new StringBuffer(tipsStrLen);
int k 0;
for(
listTips.start(); listTips.hasElement(); listTips.next(), ++k) {
    
tips[k] = (String)listTips.item();
    if(
0) {
        
buf.append("\r\n");
    }
    
buf.append(tips[k]);
}
tipsString buf.toString(); //получаем строку для сохранения в кэш 
В результате имеем:

* tips.prepared: 1218 кб
* tips. saved: 1269 кб (тут без изменений, главное что суммарно занято теперь намного меньше)

Ура, товарищи!

Замечания:
1. Советы меняются не слишком часто, т.е. обычно грузятся из кэша, при этом такой перерасход памяти не наблюдается. В основном грузятся при первом входе в чат, но ничего не мешает получить список команд при любом очередном перелёте на планету.
2. Храню в кэше всё одной строкой через \r\n, при загрузке разбиваю строку на отдельные советы. Возможно, лучше хранить отдельно каждый совет.
3. При каждом перелёте на планету советы заново создавались из строки, взятой из кэша, это память почти не расходует, но это лишняя ненужная операция*. Тоже поправил.

* время разбивки строки на компе неинформативно, а на мобилке замерять лень.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
St_AnGer (18.12.2014)