Стоит ли смягчать последствия сбора мусора?

У меня есть приложение, где профиль памяти выглядит примерно так:

Jaggy
(источник: kupio.com)

Медленный рост использования памяти вызван распределением множества маленьких, простых, переходных объектов. В ситуациях с нехваткой памяти (это мобильное приложение) накладные расходы ГХ заметны по сравнению с менее строгими объемами памяти.

Так как мы знаем, из-за природы приложения, что эти всплески будут только продолжаться, я рассматривал некоторый пул множества переходных объектов (удивительное имя). Эти объекты будут жить в течение всего жизненного цикла приложения и будут использоваться везде, где это возможно (там, где время жизни объекта короткое и очень предсказуемое).

Надеемся, что это уменьшит влияние GC за счет уменьшения количества собираемых объектов и повышения производительности.

Очевидно, что это также будет иметь свои собственные пределы производительности, поскольку "выделение" будет более дорогостоящим, и поддержание самого кэша приведет к дополнительным издержкам.

Поскольку это было бы довольно большое и навязчивое изменение большого количества кода, мне было интересно, пробовал ли кто-нибудь что-то подобное и было ли это выгодно, или были ли какие-либо другие известные способы смягчения против GC в такой ситуации, Идеи для эффективных способов управления кешем многократно используемых объектов также приветствуются.

Ответ 1

Обычно я бы сказал, что это была работа по настройке параметров GC для VM, уменьшению остроты, но для мобильных приложений это на самом деле не вариант. Поэтому, если JVms, который вы используете, не может изменить их поведение в GC, то наилучшим решением может стать старомодный пул объектов.

Библиотека Apache Commons Pool хороша для этого, хотя, если это мобильное приложение, вам могут не потребоваться накладные расходы на библиотеку.

Ответ 2

Это похоже на шаблон flyweight, подробно описанный в книге шаблонов GoF (см. ниже). Пулы объектов были не в порядке на "нормальной" виртуальной машине из-за успехов, достигнутых в сокращении создания объекта, синхронизации и накладных расходов GC. Тем не менее, они, безусловно, были вокруг в течение долгого времени, и, конечно, хорошо, чтобы попытаться проверить, помогают ли они!

Конечно, пулы объектов все еще используются для объектов, которые имеют очень дорогостоящие издержки на создание по сравнению с упомянутыми выше накладными расходами (соединения с базой данных).

Только тест скажет вам, подходит ли подход объединения к вам на ваших целевых платформах!

ИЗМЕНИТЬ. Я использовал OP, когда это возможно, для повторного использования, чтобы означать, что объекты неизменяемы. Конечно, это может быть не так, и мухомодный паттерн действительно обменивается неизменяемыми объектами (Enum является одним из примеров мухи). Измененный (read: unshareable) объект не является кандидатом для мухи, но (конечно) для пула объектов.

Ответ 3

Собственно, этот график выглядит довольно здорово для меня. GC регенерирует множество объектов, и память возвращается на тот же базовый уровень. Эмпирически это означает, что GC работает эффективно.

Проблема с пулом объектов заключается в том, что он делает ваше приложение медленнее, сложнее и потенциально более багги. Более того, на самом деле это может привести к тому, что каждый сеанс GC займет больше времени. (Все "незанятые" объекты в пуле не содержат мусора и должны быть отмечены и т.д. GC).

Ответ 4

Есть ли у J2ME коллективный сборщик мусора? Если да, то он делает много маленьких, быстрых, коллекций и, следовательно, паузы уменьшаются. Вы могли бы попытаться уменьшить пространство памяти eden (небольшое пространство памяти), чтобы увеличить частоту и уменьшить задержку для коллекций и тем самым уменьшить паузы.

Хотя, подумайте об этом, я предполагаю, что вы не можете настроить gc-поведение, потому что все, вероятно, работает в одной виртуальной машине (просто догадайтесь здесь).

Ответ 5

Вы можете проверить эту ссылку, описывающие улучшения для коллекционера Concurrent Mark Sweep, хотя я не уверен, что он доступен для J2ME. В частности, обратите внимание:

"Сопутствующий маркер sweep collector, также известный как параллельный коллектор или CMS, ориентирован на приложения, чувствительные к паузам сбора мусора".

... "В JDK 6 сборщик CMS может произвольно выполнять эти коллекции одновременно, чтобы избежать длительной паузы в ответ на вызов System.gc() или Runtime.getRuntime(). gc()., добавьте опцию"

-XX:+ExplicitGCInvokesConcurrent 

Ответ 6

Отметьте эту ссылку. В частности:

Просто перечислим некоторые из проблем пулы объектов создают: во-первых, неиспользуемые объект занимает пространство памяти без причина; GC должен обработать неиспользуемые объектов, а также бесполезные объекты без причины; И в для извлечения объекта из пул объектов синхронизация обычно требуется, что намного медленнее чем асинхронное распределение доступный изначально.

Ответ 7

Вы говорите о пуле экземпляров многократно используемых объектов.

class MyObjectPool { 
    List<MyObject> free= new LinkedList<MyObject>();
    List<MyObject> inuse= new LinkedList<MyObject>();
    public MyObjectPool(int poolsize) {
        for( int i= 0; i != poolsize; ++i ) {
           MyObject obj= new MyObject();
           free.add( obj );
        }
    }
    pubic makeNewObject( ) {
        if( free.size() == 0 ) {
            MyObject obj= new MyObject();
            free.add( obj );
        }
        MyObject next= free.remove(0);
        inuse.add( next );
        return next;
   }
   public freeObject( MyObject obj ) {
       inuse.remove( obj );
       free.add( obj );
   }
}
        return in

Ответ 8

Учитывая, что этот ответ говорит о том, что в J2ME не так много возможностей для настройки самой мусорной коллекции, то если GC является проблемой, единственным вариантом является просмотр того, как вы можете изменить свое приложение, чтобы повысить производительность/использование памяти. Возможно, некоторые из предложений в упомянутом ответе применимы к вашему приложению.

Как говорит oxbow_lakes, вы предлагаете стандартный шаблон дизайна. Однако, как и при любой оптимизации, единственный способ узнать, насколько это улучшит ваше конкретное приложение, - это реализовать и профилировать.