Ответ: Смесь: Неочевидное + Оптимизация
Загрузка советов - "лишние" 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 при сложении строк. PHP код:
Далее идёт сохранение в кэш, которое и доводит до финального уровня 1548 кб. Решение, оптимизация Сделал переменную int tipsStrLen, в которую плюсую длину каждого совета при его добавлении в список, и юзаю StringBuffer заранее указанной длины: PHP код:
* tips.prepared: 1218 кб * tips. saved: 1269 кб (тут без изменений, главное что суммарно занято теперь намного меньше) Ура, товарищи! :) Замечания: 1. Советы меняются не слишком часто, т.е. обычно грузятся из кэша, при этом такой перерасход памяти не наблюдается. В основном грузятся при первом входе в чат, но ничего не мешает получить список команд при любом очередном перелёте на планету. 2. Храню в кэше всё одной строкой через \r\n, при загрузке разбиваю строку на отдельные советы. Возможно, лучше хранить отдельно каждый совет. 3. При каждом перелёте на планету советы заново создавались из строки, взятой из кэша, это память почти не расходует, но это лишняя ненужная операция*. Тоже поправил. * время разбивки строки на компе неинформативно, а на мобилке замерять лень. |
Ответ: Смесь: Неочевидное + Оптимизация
Замутил удобоваримые для мозга сортировки образов внутри объектов.
Образы сортируются сначала по глубине depth - это слой рисования: -1 задний, 0 средний, 1 передний; затем по addOrder - порядку добавления образа в объект. Т.к. я отказался от массивов в пользу списков, то пришлось переделывать сортировку. Вот что получилось. LinkedList.sortBubble() Было: здесь в массив mas (писал ещё в те времена, когда массивы называл mas, а не arr) накапливаем количество одинаковых чисел, идущих подряд, чтобы потом отсортировать среди них по addOrder. рекламный слоган: "Тройной FOR - это по-нашему!" :) Стало: А вот наш чудесный "комплексный" компаратор, который включает в себя сравнение по двум параметрам - depth и addOrder. Добавление условий PHP код:
PHP код:
|
Ответ: Смесь: Неочевидное + Оптимизация
|
Ответ: Смесь: Неочевидное + Оптимизация
В стандартном Vector каждый метод synchronized - теоретически, из-за этого может быть медленнее.
А вообще, можно посмотреть исходники и на их основе написать свою версию, заточенную под требования конкретного случая. |
Ответ: Смесь: Неочевидное + Оптимизация
Цитата:
2. вставка в середину. в джаве есть arrayCopy, сдвигается с его помощью, наверное поэтому шустро. я обычно вставляю в список или удаляю через ссылку на узел (ListNode), т.е. по какому-то условию в цикле, когда у меня есть этот самый узел, а это быстро, т.к. нужно просто переприсвоить ссылки next, prev PHP код:
Минус списка - создаётся мелочёвка в виде узлов ListNode для каждого элемента, сборщику мусора нужно будет чистить эти узлы после удаления элементов. Igor, спасибо что напомнил про synchronized. |
Ответ: Смесь: Неочевидное + Оптимизация
Решил переделать циклы перебора списков.
Было так: PHP код:
такой код потенциально опасен - если в цикле обхода списка вызывается функция, которая должна пробегать по этому же списку, то бегунок current становится неправильным. для решения я сделал (залипуху/костыль/______) в виде дополнительной переменной storedCurrent и два метода store/restore, полагая, что более глубокой вложенности не будет. глубже вложенности пока нет, но нафиг надо. лишнее поле, работающее не универсально (вот если бы был стек сохраняемых бегунков, то другое дело), и нужное лишь для одного места в коде. Стало так: PHP код:
проход в обратном порядке делается аналогично, node = list.last(); node.next, node.item - да, они public Примечание: иногда нужно пропустить очередной next, в этом случае можно либо писать так: PHP код:
PHP код:
Теперь хочу отказаться от этого, чтобы не было путаницы. пример: вызываешь в цикле метод list.skipStep(), надеешься что он не подведёт, а в условии цикла про это забываешь, делая простой node = node.next; UPD: большинство списков требуют только однопаправленный проход. Есть мысль сделать односвязный список и юзать его по максимуму. Неудобство - функция удаления узла, т.к. из текущего узла никак не выцепить предыдущий, чтобы перекинуть дальше его ссылку next. Скорее всего сделаю этот список, в функцию удаления буду передавать два узла - подлежащий_удалению и предыдущий_для_него. Удалений элементов не слишком много, все они в цикле, т.е. можно легко хранить внешний указатель на prev. |
Ответ: Смесь: Неочевидное + Оптимизация
Переписал HTML- и JSON- парсеры
У нас в проекте используется псевдо-html. Часть тегов соответствуют обычному хтмл, часть - наши самодельные теги. В инете я нашёл парсер json для j2me. Но он мне показался слишком громоздким, дофигища классов. В итоге я написал свой, всего 100 строк кода (со второй попытки, первая попытка была страшновата для неподготовленного мозга). Скорость работы и потребляемую память не сравнивал с "интернетовским". Минус - юзаю рекурсию. Но мы большую вложенность не предполагаем юзать, а каких-нибудь 10 уровней внутрь мобилки тянут. А вот html парсер я сравнивал со своим же, который юзаю в текущей версии. Пока что сравнение сделал для страницы регистрации (другие популярные страницы - на очереди). текущий время: 29 мс память: 20 кб новый время: 12-15 мс память: 13 кб Сравнивал на ПК-эмуляторе, это конечно не качественно. Потом проверю на мобильнике. Ещё из фишек нового парсера - можно делать неограниченную вложенность тегов. Текущий не умеет делать вложенные однотипные теги, например таблицу в таблицу нельзя или span в span. Теперь можно. Ну и новый тег style добавили, теперь можно стили юзать, это должно сократить код, облегчить вёрстку. |
Ответ: Смесь: Неочевидное + Оптимизация
Уже давненько открыл для себя в нетбинсе фичу автоподстановки, которая предлагает варианты сразу при написании первой буквы.
По дефолту эта фича выключена. Очень ускоряет кодинг. Скрин. |
Ответ: Смесь: Неочевидное + Оптимизация
Мы зарелизили новую версию - Galaxy 9.0!
Не сегодня, пораньше. Вчера я уже допилил багфиксы для 9.0.4. К делу. На некоторых телефонах прога закрывалась сразу при запуске, выдавая NullPointerException. Включая 2 наших тестовых телефона, и это хорошо - было на чём разбираться. Сроки горели, пришлось с багом релизить. (Но мы не афишировали обнову сразу, лишь спустя несколько дней), так что не было поголовных апдейтов. Тем более что это j2me, нет автообновлений. Жалобы про нулпоинтер, конечно, посыпались в службу поддержки. Начал разбираться. Встал вопрос - как это дебажить. В андроиде халява - по шнуру тебе в дебаг сливается стек с ошибкой, видишь откуда корни, а на j2me хрен, - даже текстом на экран просто так не выведешь, т.к. при появлении ошибки вылазит системный алерт и ничего не успеешь понять. В итоге я сделал функцию waitForKey, которая крутит бесконечный цикл, пока не нажмём клавишу. Благо клавиши обрабатываются в отдельном системном потоке, и мы их можем ловить при наличии бесконечного цикла в главном потоке. Комбинируя waitForKey с выводом на экран каждого шага загрузки ресурсов, я обнаружил, что проблема в функции загрузки текста из файла: Изучил её внутренности, вроде всё в порядке, но я выдвинул гипотезу-причину, переделал, но не помогло. :) [гипотеза: некоторые телефоны выдают некорректную длину данных в потоке: int size = dis.available();] Дальнейший пошаговый дебаг выявил окончательную причину. Так в чём же тут дело? Ответ: Попутно узнал, что в конструкции try - catch - finally секция finally выполнится, даже если в try есть досрочный return. |
Ответ: Смесь: Неочевидное + Оптимизация
Узнал интересную штуку для дебага - определение вложенности вызовов функций:
Код:
try { Блин, это гениально! Помогло мне разобраться в длинной череде вызовов: |
Ответ: Смесь: Неочевидное + Оптимизация
Прокрутка браузерных страниц.
Раньше у меня при прокрутке страницы делался сдвиг всех элементов формы. В итоге для жирных страниц совершалось много теледвижений, проходов по вложенным тегам. Теперь просто сдвигаю канвас при отрисовке страницы. Дополнительно пришлось * поправить функцию setClip, т.к. при сдвиге канваса область отсечения также уезжает. * поправить пункцию isElementInView, т.к. раньше в ней завязка была на то что меняем координаты самих элементов. |
Ответ: Смесь: Неочевидное + Оптимизация
С функциями graphics.setClip() и graphics.translate() оказалось больше проблем, чем хотелось бы.
Прокачал класс Viewport - хэлпер для работы с клиппингом. Н-р, он умеет делать lock/unlock, чтобы последующие установки клипа не выходили за эту залоченную область. Что узнал: 1. Важен порядок вызова функций setClip => translate != translate => setClip при установке области клипа учитывается текущий сдвиг координат, но все последующие никак не влияют, запоминает именно сдвиг в момент установки клипа. 2. Реальные координаты клипа g.getClipX() и g.getClipY() - возвращаются значения с учётом сдвига координат. 3. g.translate(int x, int y) - это не передвинуть канвас в указанную точку, а сдвинуть на указанное количество относительно текущей позиции. могли бы написать в доке dx, dy для понятности. 4. Внутренности графикса по части клипа и транслэйта сложнее, чем думал (см. скрин) |
Ответ: Смесь: Неочевидное + Оптимизация
Если кто-то использует NetBeans IDE и любит тёмное оформление, то можете установить Darcula плагин.
https://github.com/Revivius/nb-darcula Он делает тёмным весь интерфейс, а не только область кода, как некоторые. Портал с плагинами недоступен, пришлось компилить из исходников. скачать из дропбокса nb-darcula-1.5.nbm |
Часовой пояс GMT +4, время: 04:45. |
vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot