Стоит ли смягчать последствия сбора мусора? - PullRequest
11 голосов
/ 05 августа 2009

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

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

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

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

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

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

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

Ответы [ 8 ]

6 голосов
/ 05 августа 2009

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

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

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

РЕДАКТИРОВАТЬ - Я взял OP «повторно использовать, где это возможно» , чтобы обозначить, что объекты были неизменными. Конечно, это может быть не так, и шаблон flyweight на самом деле касается общих неизменяемых объектов (Enum s - один из примеров flyweight). Изменяемый (читай: не доступный) объект не является кандидатом в шаблон flyweight, но (конечно) для пула объектов.

2 голосов
/ 05 августа 2009

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

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

2 голосов
/ 05 августа 2009

На самом деле, этот график выглядит довольно здоровым для меня. GC восстанавливает много объектов, и память возвращается к тому же базовому уровню. Опыт показывает, что ГХ работает эффективно.

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

2 голосов
/ 05 августа 2009

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

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

1 голос
/ 08 августа 2009

Проверить эту ссылку . В частности:

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

1 голос
/ 05 августа 2009

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

"Параллельный сборщик меток, также известный как параллельный сборщик или CMS, предназначен для приложений, чувствительных к паузах сбора мусора."

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

-XX:+ExplicitGCInvokesConcurrent 
0 голосов
/ 05 августа 2009

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

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

0 голосов
/ 05 августа 2009

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...