使用PermGen空间或滚动我自己的实习方法?

Ada*_*ski 8 java garbage-collection permgen string-interning

我正在编写一个Codec来处理使用定制有线协议通过TCP发送的消息.在解码过程中,我创建了许多Strings,BigDecimals和日期.客户端 - 服务器访问模式意味着客户端发出请求然后解码数千个响应消息是常见的,这会导致大量的重复 String s,BigDecimals等.

因此我创建了一个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));
Run Code Online (Sandbox Code Playgroud)

我的问题:我使用InternPoolBigDecimal,但我应该还可以考虑使用它String 来代替 Stringintern()方法,我相信使用的PermGen空间?使用PermGen空间有什么好处?

Joa*_*uer 5

如果您已经有这样的InternPool类,它认为使用它比为字符串选择不同的实习方法更好.特别是因为它String.intern()似乎提供了比你实际需要更强大的保证.您的目标是减少内存使用量,因此实际上不需要在JVM的生命周期内实现完美的实习.

另外,我会使用Google Collections 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;
        }
      });
Run Code Online (Sandbox Code Playgroud)

这将为您提供(正确实现)弱键和值,线程安全,旧条目的自动清除以及非常简单的界面(简单,众所周知Map).为了确保你也可以使用它来包装,Collections.immutableMap()以避免糟糕的代码搞乱它.

  • ...此外,Guava 现在有`Interners`,所以我不确定`Map​​Maker` 方法是否是必要的。 (2认同)

Ste*_*n C 3

JVM 池可能String.intern()会更快。AFAIK,它是在本机代码中实现的,因此它应该WeakHashMap比使用和实现的池更快并且使用更少的空间WeakReference。您需要进行一些仔细的基准测试来确认这一点。

但是,除非您有大量长期存在的重复对象,否则我怀疑实习(无论是在 permGen 中还是在您自己的池中)会产生很大的影响。如果唯一对象与重复对象的比率太低,则驻留只会增加活动对象的数量(使 GC 花费更长的时间),并由于驻留的开销等而降低性能。因此,我还主张对“实习生”与“无实习生”方法进行基准比较。