2017-11-12 2 views
2

私は多くの文字列を扱わなければならない取引処理アプリケーションに取り組んでいます。これらの文字列の中には、Trade IDなどの繰り返しがないものと、プロダクトIDなど頻繁に繰り返すものがあります。Javaのすべての文字列をインターンにすることによるパフォーマンスへの影響は?

トレードメッセージ(JSON)を解析する際に、すべての取引属性を汎用ステップとして扱い、メモリ使用量を減らして平等チェックを高速化することを検討しています。

私の質問は、この移動で意図せずパフォーマンスが低下する可能性があるかどうかです。

+5

は、あなたはその時点でいますアプリケーションをチューニングして有効な問題であるとか、これが正当な理由なしにやっていると思っている時期尚早なマイクロ最適化ですか?測定、測定、測定... – Kayaman

+0

私は、インターンは、すべての文字列を入力JSONから抽出してからインターンする必要があるため、解析を高速化できるとは思いません。だから、私は、構文解析が遅くなると思うが、後で助けるかもしれない。バイトとマッチで動作する[JSONパーサ](https://github.com/square/moshi/blob/master/moshi/src/main/java/com/squareup/moshi/ClassJsonAdapter.java#L158)があります既知の属性名は文字列を生成しません。 – maaartinus

答えて

3

通常、メモリを節約するには、一般的な文字列を重複排除することをお勧めします。
重複排除にはString.internを使用しないでください。

  • String.internはネイティブメソッドです。各コールにはさらにJNI overheadが発生します。
  • すべてのJVMパート間で共有される内部ハッシュテーブルを吹き飛ばします(クラスローディングなど)。
  • 文字列テーブルの既定の容量が十分ではなく、バケット数が一定です。
  • JVMがこの内部ハッシュテーブルをスキャンし、おそらく世界の段階で再ハッシュするので、GCの一時停止が増加する可能性があります。
  • 詳細はthis presentationです。

普通のHashMapまたはConcurrentHashMapは、この作業のためにはるかに優れています。

次のベンチマークは、1Mの文字列のセットに[Concurrent]HashMap.putIfAbsentString.internのパフォーマンスを比較しています

@State(Scope.Benchmark) 
public class Dedup { 
    private static final HashMap<String, String> HM = new HashMap<>(); 
    private static final ConcurrentHashMap<String, String> CHM = new ConcurrentHashMap<>(); 

    private static final int SIZE = 1024 * 1024; 
    private static final String[] STRINGS = new Random(0).ints(SIZE) 
      .mapToObj(Integer::toString) 
      .toArray(String[]::new); 

    int idx; 

    @Benchmark 
    public String intern() { 
     String s = nextString(); 
     return s.intern(); 
    } 

    @Benchmark 
    public String hashMap() { 
     String s = nextString(); 
     String prev = HM.putIfAbsent(s, s); 
     return prev != null ? prev : s; 
    } 

    @Benchmark 
    public String concurrentHashMap() { 
     String s = nextString(); 
     String prev = CHM.putIfAbsent(s, s); 
     return prev != null ? prev : s; 
    } 

    private String nextString() { 
     return STRINGS[++idx & (SIZE - 1)]; 
    } 
} 

JDK 9の結果(小さい方が良いです):

Benchmark    Mode Cnt Score Error Units 
Dedup.concurrentHashMap avgt 10 91,208 ± 0,569 ns/op 
Dedup.hashMap   avgt 10 73,917 ± 0,602 ns/op 
Dedup.intern    avgt 10 832,700 ± 73,402 ns/op 
+0

Guavaの[Interners](https://google.github.io/guava/releases/23.0/api/docs/com/google/common/collect/Interners.html)が適切なツールだと思います。 AFAIKでは、インターンシップテーブルのサイズはまったく変更されませんが、 '-XX:StringTableSize = 1000003'がresqueにあります。 Java 8のデフォルトサイズは60013であり、遅さを説明しています。サザーサイズでは、使えるかもしれません。 – maaartinus

+0

JVMは文字列テーブルのサイズを変更することはできません。 – apangin

+0

@apangin、詳細な説明は大変ありがとうございます –

関連する問題