Я пишу Кодек для обработки сообщений, отправленных по TCP с помощью сделанного на заказ проводного протокола. Во время процесса декодирования я создаю много String
s, BigDecimal
s и даты. Схемы доступа клиент-сервер означают, что клиенту свойственно выпустить запрос и затем декодировать тысячи ответных сообщений, который приводит к большому количеству дубликата String
s, BigDecimal
s, и т.д.
Поэтому я создал InternPool<T>
класс, разрешающий мне интернировать каждый класс объекта. Внутренне, пул использует a 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?
Вероятно, пул JVM String.intern ()
будет работать быстрее. AFAIK, он реализован в собственном коде, поэтому он должен быть быстрее и использовать меньше места, чем пул, реализованный с использованием WeakHashMap
и WeakReference
. Чтобы подтвердить это, вам нужно будет провести тщательный сравнительный анализ.
Однако, если у вас нет огромного количества долгоживущих повторяющихся объектов, я сомневаюсь, что интернирование (либо в permGen, либо с вашими собственными пулами) будет иметь большое значение. А если соотношение уникальных и повторяющихся объектов слишком низкое, интернирование просто увеличит количество живых объектов (что заставит сборщик мусора занять больше времени) и снизит производительность из-за накладных расходов на интернирование и т. Д. Так что я бы также поддержал сравнение подходов «стажер» и «не стажер».
Если у вас уже есть такой класс 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;
}
});
Это даст вам (правильно реализовано ) слабые ключи и значения, безопасность потоков, автоматическая очистка старых записей и очень простой интерфейс (простая, хорошо известная карта
). Конечно, вы также можете обернуть его, используя Collections.immutableMap ()
, чтобы избежать неправильного кода.