LINUX.ORG.RU

Работа с большими объемами данных

 ,


1

2

Здравстуйте.

Есть сервлет, к нему делаются GET-запросы и передаются параметры from и to (UNIX-timestamp) - период, за который нужно вернуть данные.
Данные возвращаются в формате JSON.
В общем случае, каждый элемент возвращаемых данных представляет собой 2 поля - timestamps и data, где timestamps - массив timestamp'ов, где каждый - timestamp начала дня (и все в интервале от from до to, в порядке возрастания; разница между соседними - 86400). А data - массив значений (некоторое число, либо null, если данных за данный день нет; в данном случае 0 - это значение - и важно различать когда 0, а когда null).
Пример:

{
  "data": [
           25,
           null,
           35
          ],
  "timestamps":[
                1354910400,
                1354996800,
                1355083200
               ]
}
Сейчас делается следующим образом:
1. from округляется до начала дня, to - до начала следующего дня и массив timestamps в цикле заполняется long'ами от from до to с шагом в 86400
2. Вызываются различные методы и результаты записываются в HashMap'ы<Long, Long>, где ключ - timestamp начала дня, а значение - значение на данный день.
3. Создается StringBuilder и для каждого HashMap'а делается:
- пробегаем по всем элементам массива timestamps
- если в текущем HashMap'е элемент по ключу timestamps[n] равен null, то в StringBuilder делаем append(«null»)
- если же на данный день у нас есть данные - append'им их

Потом все переводится в валидный JSON и конце концов делается response.getWriter.print(result) - возвращается результат

В общем-то, все работает, все удобно, но при большом количестве запросов (а каждый запрос довольно тяжелый) - в куче накапливается огромное количество этих HashMap'Ов - они начинают занимать где-то 800МБ.
Т.е. ситуация чревата тем, что heap space кончится. Хотя по сути, данные долго хранить не надо - просто посчитать 1 раз, да вернуть их в respons'е

Вопросы:
1. Как организовать данные и минимизировать затраты памяти? Использовать вместо HashMap'ов обычные массивы (хотя с HashMap'ами работать намного удобнее)?
2. Как эффективно в данном случае работать с памятью? Делать myHashMap.clear() не имеет смысла,так? Вызывать насильно System.gc() - слишком радикально, да и сильно замедлит работу. Как в данном случае быть?
Решат ли проблему WeakReference's?

Спасибо.

★★★★★

Последнее исправление: kovrik (всего исправлений: 1)

Первый раз невнимательно прочитал, написал пурги, извините. Я думаю что если у вас есть from и to, то их и передавайте. Зачем арифметическая прогрессия если известно начало, конец и шаг.

Потом

а каждый запрос довольно тяжелый

С какой точки зрения? Сложная выборка? - считайте периодически для нужных значений, записывайте готовые результаты в отдельную таблицу. Много данных за один запрос? - тут ваш сервер легко затроллить сделав много запросов и начать их максимально медленно качать, нужно подумать о event-driven model. Нужно понять как у вас качают эти данные, есть ли смысл просто итерировать по курсору и отдавать сразу в сеть без промежуточных структур данных

vertexua ★★★★★
()

1. судя по описанию, массив timestamps не нужен вовсе (i-тый элемент равен from+i*86400).

2. отсюда следует, что, видимо, хешмапы не нужны тоже — достаточно диапазон данных по дням [from,to] представить в виде массива data, i-тый элемент которого соответствует i-тому дню.

это вроде бы должно решить все описанные проблемы.

anonymous
()

Если у тебя хешмапы не чистятся сборщиком мусора, значит их кто то держит после обработки запроса, решай эту проблему. Если не держит и они собираются то проблемы нет. Откуда цифра 800 Мб?

Legioner ★★★★★
()

Я не очень вчитывался в алгоритм, но если у тебя и правда большой объем памяти занят HashMap<Long,Long>, то советую использовать Long2LongOpenHashMap из пакета fastutil. Так будет и компактнее по памяти, и быстрее. Обрати внимание, что для наибольшей эффективности надо использовать собственное API этого класса, а не методы Collections Framework.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

А не правильно прочитал, я думаю у тебя один большой hashmap, а не куча маленьких

maxcom ★★★★★
()
Ответ на: комментарий от Legioner

Да вот фиг знает, по идее, чистятся. HashMap'ы не статические. Просто при запросе в сервлете вызывается метод, который возвращает HashMap. Потом данные выводятся writer'ом и все. Как бы, после того, как сервлет вернул результат - никто не должен держать ссылки на эти хэшмапы.

Как вариант - просто не хватало дефолтной HeapSize. Сейчас увеличил - за 4 дня никаких ошибок OutOfMemory.

kovrik ★★★★★
() автор топика
Ответ на: комментарий от kovrik

Просто при запросе в сервлете вызывается метод, который возвращает HashMap

Это нельзя переписать? Если мапу кто-то постоянно создает, причем такую глупую, то что тут поделаешь

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Переписать на что? Ну, будет возвращать не HashMap, а ArrayList, например - это шило на мыло. Тут, скорее, по-другому сам процесс хранения и отдачи данных нужно организовать.

kovrik ★★★★★
() автор топика
Ответ на: комментарий от kovrik

Сколько у вас чисел за раз бывает максимально? И второй вопрос, вы может избавиться от timestapms как уже много раз посоветовали в этом треде?

vertexua ★★★★★
()
Ответ на: комментарий от kovrik

Ну, будет возвращать не HashMap, а ArrayList, например - это шило на мыло.


Если можно вернуть лист, значит можно сделать работу с потоками - т.е. не создавать и возвращать коллекцию, а сразу писать в аут.

vtVitus ★★★★★
()
Ответ на: комментарий от vertexua

От них уже избавился. Максимума чисел нет. Зависит от from и to.

kovrik ★★★★★
() автор топика
Ответ на: комментарий от vtVitus

Если можно вернуть лист, значит можно сделать работу с потоками - т.е. не создавать и возвращать коллекцию, а сразу писать в аут.

А вот это уже хорошая идея, но пока не очень понятно как реализовать ее

kovrik ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.