简介

String对象有个非凡的StringTable字符串常量池,为了缩小Heap中生成的字符串的数量,举荐尽量间接应用String Table中的字符串常量池中的元素。

那么String.intern的性能怎么样呢?咱们一起来看一下。

String.intern和G1字符串去重的区别

之前咱们提到了,String.intern办法会返回字符串常量池中的字符串对象的援用。

而G1垃圾回收器的字符串去重的性能其实和String.intern有点不一样,G1是让两个字符串的底层指向同一个byte[]数组。

有图为证:

上图中的String1和String2指向的是同一个byte[]数组。

String.intern的性能

咱们看下intern办法的定义:

public native String intern();

大家能够看到这是一个native的办法。native底层必定是C++实现的。

那么是不是native办法肯定会比java办法快呢?

其实native办法有这样几个耗时点:

  1. native办法须要调用JDK-JVM接口,实际上是会浪费时间的。
  2. 性能会受到native办法中HashTable实现办法的制约,如果在高并发的状况下,native的HashTable的实现可能成为性能的制约因素。

举个例子

还是用JMH工具来进行性能剖析,咱们应用String.intern,HashMap,和ConcurrentHashMap来比照剖析,别离调用1次,100次,10000次和1000000。

代码如下:

@State(Scope.Benchmark)@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)@Fork(value = 1, jvmArgsPrepend = "-XX:+PrintStringTableStatistics")@Warmup(iterations = 5)@Measurement(iterations = 5)public class StringInternBenchMark {    @Param({"1", "100", "10000", "1000000"})    private int size;    private StringInterner str;    private ConcurrentHashMapInterner chm;    private HashMapInterner hm;    @Setup    public void setup() {        str = new StringInterner();        chm = new ConcurrentHashMapInterner();        hm = new HashMapInterner();    }    public static class StringInterner {        public String intern(String s) {            return s.intern();        }    }    @Benchmark    public void useIntern(Blackhole bh) {        for (int c = 0; c < size; c++) {            bh.consume(str.intern("doit" + c));        }    }    public static class ConcurrentHashMapInterner {        private final Map<String, String> map;        public ConcurrentHashMapInterner() {            map = new ConcurrentHashMap<>();        }        public String intern(String s) {            String exist = map.putIfAbsent(s, s);            return (exist == null) ? s : exist;        }    }    @Benchmark    public void useCurrentHashMap(Blackhole bh) {        for (int c = 0; c < size; c++) {            bh.consume(chm.intern("doit" + c));        }    }    public static class HashMapInterner {        private final Map<String, String> map;        public HashMapInterner() {            map = new HashMap<>();        }        public String intern(String s) {            String exist = map.putIfAbsent(s, s);            return (exist == null) ? s : exist;        }    }    @Benchmark    public void useHashMap(Blackhole bh) {        for (int c = 0; c < size; c++) {            bh.consume(hm.intern("doit" + c));        }    }    public static void main(String[] args) throws RunnerException {        Options opt = new OptionsBuilder()                .include(StringInternBenchMark.class.getSimpleName())                .build();        new Runner(opt).run();    }}

输入后果:

Benchmark                                 (size)  Mode  Cnt          Score          Error  UnitsStringInternBenchMark.useCurrentHashMap        1  avgt    5         34.259 ±        7.191  ns/opStringInternBenchMark.useCurrentHashMap      100  avgt    5       3623.834 ±      499.806  ns/opStringInternBenchMark.useCurrentHashMap    10000  avgt    5     421010.654 ±    53760.218  ns/opStringInternBenchMark.useCurrentHashMap  1000000  avgt    5   88403817.753 ± 12719402.380  ns/opStringInternBenchMark.useHashMap               1  avgt    5         36.927 ±        6.751  ns/opStringInternBenchMark.useHashMap             100  avgt    5       3329.498 ±      595.923  ns/opStringInternBenchMark.useHashMap           10000  avgt    5     417959.200 ±    62853.828  ns/opStringInternBenchMark.useHashMap         1000000  avgt    5   79347127.709 ±  9378196.176  ns/opStringInternBenchMark.useIntern                1  avgt    5        161.598 ±        9.128  ns/opStringInternBenchMark.useIntern              100  avgt    5      17211.037 ±      188.929  ns/opStringInternBenchMark.useIntern            10000  avgt    5    1934203.794 ±   272954.183  ns/opStringInternBenchMark.useIntern          1000000  avgt    5  418729928.200 ± 86876278.365  ns/op

从后果咱们能够看到,intern要比其余的两个要慢。

所以native办法不肯定快。intern的用途不是在于速度,而是在于节约Heap中的内存应用。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/jvm-string-intern-performance/

本文起源:flydean的博客

欢送关注我的公众号:程序那些事,更多精彩等着您!