Использовать метод PermGen space или метод roll-my-own? - PullRequest
8 голосов
/ 19 мая 2010

Я пишу кодек для обработки сообщений, отправляемых по TCP, с использованием специального проводного протокола. В процессе декодирования я создаю число String s, BigDecimal s и даты. Шаблоны доступа клиент-сервер означают, что для клиента характерно выдавать запрос и затем декодировать тысячи ответных сообщений, что приводит к большому количеству дубликатов String с, BigDecimal с, и т.д.

Поэтому я создал InternPool<T> класс, позволяющий мне интернировать каждый класс объекта. Внутренне, пул использует WeakHashMap<T, WeakReference<T>>. Например:

InternPool<BigDecimal> pool = new InternPool<BigDecimal>();

...

// Read BigDecimal from in buffer and then intern.
BigDecimal quantity = pool.intern(readBigDecimal(in));

Мой вопрос: я использую InternPool для BigDecimal, но стоит ли мне использовать его также для String вместо String intern() метода, который, я считаю, использует PermGen пространство? В чем преимущество использования пространства PermGen?

Ответы [ 2 ]

5 голосов
/ 19 мая 2010

Если у вас уже есть такой класс InternPool, лучше использовать его, чем выбирать другой метод интернирования для строк. Тем более, что String.intern() дает гораздо более сильную гарантию, чем вам действительно нужно. Ваша цель состоит в том, чтобы уменьшить использование памяти, поэтому на самом деле идеальное интернирование для жизненного цикла JVM на самом деле не нужно.

Кроме того, я бы использовал Коллекции Google MapMaker, чтобы создать InternPool, чтобы избежать повторного создания колеса:

Map<BigDecimal,BigDecimal> bigDecimalPool = new MapMaker()
    .weakKeys()
    .weakValues()
    .expiration(1, TimeUnits.MINUTES)
    .makeComputingMap(
      new Function<BigDecimal, BigDecimal>() {
        public BigDecimal apply(BigDecimal value) {
          return value;
        }
      });

Это даст вам (правильно реализованные) слабые ключи и значения, безопасность потоков, автоматическую очистку старых записей и очень простой интерфейс (простой, хорошо известный Map). Чтобы быть уверенным, вы также можете обернуть его, используя Collections.immutableMap(), чтобы избежать неправильного кода.

3 голосов
/ 19 мая 2010

Вероятно, пул String.intern() JVM будет быстрее. AFAIK, он реализован в собственном коде, поэтому он должен быть быстрее и использовать меньше места, чем пул, реализованный с использованием WeakHashMap и WeakReference. Вам нужно будет провести тщательный сравнительный анализ, чтобы подтвердить это.

Однако, если у вас нет огромного количества долгоживущих дублирующих объектов, я сомневаюсь, что стажировка (либо в permGen, либо с вашими собственными пулами) будет иметь большое значение. И если отношение уникальных к дублирующимся объектам слишком низкое, то интернирование просто увеличит количество живых объектов (что заставит GC занимать больше времени) и снизит производительность из-за издержек интернирования и так далее. Так что я бы также выступил за сопоставление подходов «стажер» и «без стажера».

...