2012-12-15 3 views
3

У меня очень странная проблема с GC в Java. Я бегу-й следующий фрагмент кода:Переполнение верхнего пространства кучи старого

while(some condition){ 
     //do a lot of work... 
     logger.info("Generating resulting time series..."); 
     Collection<MetricTimeSeries> allSeries = manager.getTimeSeries(); 
     logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size())); 

     //for (MetricTimeSeries series : allSeries) { 
      // just empty loop 
     //} 
} 

Когда я смотрю в JConsole, при перезапуске каждой итерации цикла, мой старый ген кучи пространства, если я вручную заставить GC, имеет размер около 90 МБ. Если я раскомментировать петлю, как этот

while(some condition){ 
     //do a lot of work... 
     logger.info("Generating resulting time series..."); 
     Collection<MetricTimeSeries> allSeries = manager.getTimeSeries(); 
     logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size())); 

     for (MetricTimeSeries series : allSeries) { 
      // just empty loop 
     } 
} 

Даже если заставить его обновить, он не будет падать ниже 550mb. Согласно профилировщику yourKit, объекты TimeSeries доступны через локальный var (коллекцию) основного потока, сразу после GC при перезапуске новой итерации ... И коллекция огромна (временные ряды по 250K.) ... Wyy is это происходит и как я могу «бороться» с этим (неправильным?) поведением?

+0

Что делает manager.getTimeSeries(); делать? Кроме того, что делает его функция итератора возвращаемого значения? –

+0

Itis создает ArrayList всех временных рядов, о которых он знает (есть базовые объекты, которые, в свою очередь, делают то же самое, для всех временных рядов они управляют). В конце, один большой ArrayList является сборкой и возвратом, и итератором является только стандартный java-итератор для List – Bober02

+0

, он когда-либо выходит в то время как (какое-то условие)? стр. его реальная трудная попытка решить проблему, которая является черным ящиком – bluesman

ответ

1

Поскольку вы строите (большой) ArrayList временных рядов, он будет занимать кучу до тех пор, пока на ней ссылаются, и будет повышаться до старого, если он останется достаточно долго (или если молодое поколение слишком мало для фактически держите его). Я не уверен, как вы связываете информацию, которую видите в JConsole или Yourkit, с определенной точкой в ​​программе, но до тех пор, пока пустой цикл не будет оптимизирован несколькими проходами JIT, цикл while займет больше времени и сохранит коллекцию дольше, что может объяснить воспринимаемую разницу, в то время как на самом деле их не так много.

В этом нет ничего неправильного. Если вы не хотите потреблять столько памяти, вам нужно изменить свой Collection, чтобы он не был заполнен ArrayList, а ленивая коллекция, большая часть потока (если вы когда-либо делали обработку XML, считайте DOM против SAX), который оценивается по мере его повторения. Если вам не нужна вся коллекция для сортировки, это выполнимо, тем более, что вы, кажется, говорите, что коллекция представляет собой конкатенацию подкатегорий, возвращаемых базовыми объектами.

Если вы можете изменить тип возвращаемого из Collection в Iterable, можно, например, использовать Guava «s FluentIterable.transformAndConcat() преобразовать коллекцию базовых объектов, лениво-оцениваемой Iterable конкатенации их временных рядов. Конечно, размер коллекции больше не доступен напрямую (и если вы попытаетесь получить его независимо от итерации, вы будете оценивать ленивую коллекцию дважды).

2

Да, сборщик мусора может быть таинственным .. но бьет управления собственной памяти;)

Коллекции и карты есть способ подвешивания на ссылки дольше, чем вы мощь как и, таким образом, предотвращая сбор мусора, когда вы можете ожидать. Как вы заметили, установка ссылки allSeries на null сама по себе будет отмечать ее для сбора мусора, и, таким образом, это содержимое также подходит для захватов. Другим способом было бы позвонить allSeries.clear(): это отменит все его объекты MetricTimeSeries, и они будут бесплатными для сбора мусора.

Почему удаление петли обойти эту проблему также? Это более интересный вопрос. У меня возникает соблазн предложить компилятору оптимизировать ссылку на allSeries .. но вы все еще звоните allSeries.size(), так что он не может полностью оптимизировать ссылку.

Для мутной воды разные компиляции (и настройки) ведут себя по-разному и используют разные сборщики мусора, которые сами ведут себя по-разному. Трудно точно сказать, что происходит под капотом, без дополнительной информации.

+0

Передача коллекции другому методу обработки делает трюк также .... WTF ???? – Bober02

+0

btw, заменяя обычный итератор и вызывающий iterator.remove, ничего не меняет – Bober02

Смежные вопросы