JVM 시리즈 의 String.intern 성능 분석

5288 단어 String.intern
String 대상 에 특수 한 StringTable 문자열 상수 탱크 가 있 습 니 다.Heap 에서 생 성 된 문자열 의 수 를 줄 이기 위해 String Table 의 문자열 상수 탱크 에 있 는 요 소 를 직접 사용 하 는 것 을 추천 합 니 다.
그럼 String.intern 의 성능 은 어 떻 습 니까?같이 보 자.
String.intern 과 G1 문자열 의 차이 점 제거
앞서 언급 했 듯 이 String.intern 방법 은 문자열 상수 탱크 의 문자열 대상 에 대한 인용 을 되 돌려 줍 니 다.
G1 쓰레기 수 거 기의 문자열 을 무 게 를 줄 이 는 기능 은 String.intern 과 조금 다 릅 니 다.G1 은 두 문자열 의 아래쪽 을 같은 byte[]배열 로 가리 키 는 것 입 니 다.
증거 로 삼 을 그림 이 있다.

위의 그림 에서 String 1 과 String 2 는 같은 byte[]배열 을 가리 키 고 있 습 니 다.
String.intern 의 성능
인터넷 방법의 정 의 를 봅 시다.

public native String intern();
보시 다시 피 이것 은 native 의 방법 입 니 다.native 밑바닥 은 틀림없이 C++가 실 현 된 것 이다.
그럼 네 이 티 브 방법 이 자바 방법 보다 빠 를 까요?
사실 native 방법 은 이렇게 몇 가지 시간 이 걸 립 니 다.
  • native 방법 은 JDK-JVM 인 터 페 이 스 를 호출 해 야 하 는데 사실은 시간 을 낭비 할 수 있다
  • 성능 은 native 방법 에서 HashTable 실현 방법의 제약 을 받는다.만약 에 높 은 병발 상황 에서 native HashTable 의 실현 은 성능 의 제약 요소 가 될 수 있다
  • 예 를 들다
    아니면 JMH 도구 로 성능 분석 을 할 까요?저 희 는 String.intern,HashMap,Concurrent HashMap 을 사용 하여 비교 분석 을 하고 각각 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  Units
    StringInternBenchMark.useCurrentHashMap        1  avgt    5         34.259 ±        7.191  ns/op
    StringInternBenchMark.useCurrentHashMap      100  avgt    5       3623.834 ±      499.806  ns/op
    StringInternBenchMark.useCurrentHashMap    10000  avgt    5     421010.654 ±    53760.218  ns/op
    StringInternBenchMark.useCurrentHashMap  1000000  avgt    5   88403817.753 ± 12719402.380  ns/op
    StringInternBenchMark.useHashMap               1  avgt    5         36.927 ±        6.751  ns/op
    StringInternBenchMark.useHashMap             100  avgt    5       3329.498 ±      595.923  ns/op
    StringInternBenchMark.useHashMap           10000  avgt    5     417959.200 ±    62853.828  ns/op
    StringInternBenchMark.useHashMap         1000000  avgt    5   79347127.709 ±  9378196.176  ns/op
    StringInternBenchMark.useIntern                1  avgt    5        161.598 ±        9.128  ns/op
    StringInternBenchMark.useIntern              100  avgt    5      17211.037 ±      188.929  ns/op
    StringInternBenchMark.useIntern            10000  avgt    5    1934203.794 ±   272954.183  ns/op
    StringInternBenchMark.useIntern          1000000  avgt    5  418729928.200 ± 86876278.365  ns/op
    결과적으로 우 리 는 인터넷 이 다른 두 개 보다 느리다 는 것 을 알 수 있다.
    그래서 네 이 티 브 방법 이 빠 르 지 는 않 아 요.intern 의 용 도 는 속도 가 아니 라 힙 의 메모리 사용 을 절약 하 는 데 있다.
    JVM 시리즈 의 String.intern 의 성능 분석 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.String.intern 의 성능 에 관 한 더 많은 내용 은 저희 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기