2017-12-04 7 views
1

私は、Jaxb2を使用してXMLにアンマーシャリングするコストを、いくらか長い(48文字)タグ名を持つ大きな(1.7mb)XMLペイロードを使用して測定しました。サンプリングモードでJProfilerを実行すると、文字列インターワーキング作業は時間の無駄な部分であることがわかりました。Jaxb2内の文字列インターンシップを無効にすると、Fastinfosetストリームからのアンマーシャリングが高速化されます。なぜそれを無効にするのは難しいですか?

私はいくつかの調査を行い、Jaxbは文字列を使わないモードで実行できることを発見しました。私の理論では、非マーシャリング中に文字列をインターンリングしないと、インターン処理中にすべてのタグ名文字列をハッシュする必要がないため、より多くのヒープメモリを使用してパフォーマンスを向上させることができます。

私はJAXBのインターンの挙動を抑制するために使用される方法は、(にXMLStreamReaderを実装して)私のFastinfoset「StAXDocumentParser」に「org.codehaus.stax2.internNames」と「org.codehaus.stax2.internNsUris」プロパティを設定することでした。 Jaxbが文字列をインターンに入れないようにするために、なぜこれらをtrueに設定しなければならないのかは、100%明確ではありませんが、それはどのように動作するのかです。

これらのJUnit駆動型テストは、私は、JAXBの文字列のインターン動作を無効にすると、大きなパフォーマンスの違いがあると結論するために使用するものです。

https://github.com/gjd6640/fastinfoset-performance-evaluation

だから私の質問は、マルチパートである:

1)重要なことを誤解していて、Jaxbの文字列インターンシップの動作を最初から無効にしようとしてはいけませんか?

2)Jaxbにインターンの文字列を渡すより良い方法はありますか? "StAXManager"クラスでは、これらのWoodstox指向のプロパティを設定することはできません。このテストでは、以下のようにStAXManagerを拡張して問題をハックしました。これは私が生産で使用したくないハックです。 JaxbがWoodstoxストリームからアンマーシャリングしているときに、Woodstoxがすでにインターンシップを行っているかどうか、そしてJaxbがそのプロセスのそのステップを無効にすることによって反応するかどうかを調べるというのが私の考えです。私はJaxbライブラリのロジックを抱いているので、これについてもっと良い方法が欲しいです。

package com.sun.xml.fastinfoset.stax; 
public class JaxbStringInternSuppressionStaxManager extends StAXManager { 
    public JaxbStringInternSuppressionStaxManager() { 
     // Add to the allowable list of feature names so that the user may set these "StAXInputFactory" properties 
     super.features.put("org.codehaus.stax2.internNames", null); 
     super.features.put("org.codehaus.stax2.internNsUris", null); 
    } 
} 

更新:いつものように

、 "よく置く質問はハーフ答えです"。私はちょうど "com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector"クラスが "com.sun.xml"クラスかどうかを調べるというこの質問を起草している間に気づいた。内部 .fastinfoset.stax.StAXDocumentParser "は、あなたが使用しているXMLStreamReaderから割り当て可能であり、そうであれば文字列インターンを有効にしません。私の場合、私のストリームオブジェクトは "com.sun.xml.fastinfoset.stax.StAXDocumentParser"なので、インターンは無効になりません。問題は "なぜFastinfosetライブラリの内部の味のためにこれを行うのですか?"です。たぶん私は慎重にthis postを読んで答えを見つけるでしょう。

アクティブなデベロッパーユーザーグループなど、このような質問のためのより良いフォーラムがある場合は、その情報を共有してください。適切なユーザーにこの質問が表示されるように、この投稿にリンクする方法について見ていきます。

+0

補足:Oracleの "com.sun.xml.bind:jaxb-impl"ライブラリバージョン "2.1-b02-fcs"のクラスをバンドルするように見えるJDK:64ビットjdk1.8.0_121を使用しています。 –

答えて

1

私は、インターンの有無にかかわらず実際のユースケースを測定することなく、必ずしもプロファイラやテストを信頼するとは限りませんので、少し懐疑的にしてください。しかし、インターンにはいくつかの問題があります。特に、固定サイズのプール・サイズを使用するため、プールがいっぱいになると、ハッシュ・ルックアップの一定のパフォーマンスが低下してリンク・リストを検索することになります。詳細については、http://java-performance.info/string-intern-in-java-6-7-8/を参照してください。

要するに、プールサイズを-XX:StringTableSize=n(理想的には素数でなければならない)で変更し、何が起こるかを見ることができます。

-XX:+PrintStringTableStatisticsを使用すると、プログラムの終了時にプールがどのように使用され、異なるサイズを試してみるかを確認できます。

編集:これは「良い方法はありますか?」(つまり、インターンを速くする)と答えようとする試みでした。他の質問をもっと適任者に任せておきます。

+0

これは魅力的なものです。情報をありがとう。私は簡単にStringTableSizeを約2倍、次に約100倍増加させてみましたが、改善は見られませんでした。私のテストでは、JVMのデフォルトのハッシュマップサイズ60kのうち3090を使用しているようです。 StringTable統計: バケット数:60013 = 480104バイト、平均8.000 エントリ数:3090 = 74160バイト、平均24.000 リテラルの数:3090 = 256072バイト、平均82.871 合計フットプリント:= 810336バイト –

0

ソリューションオプション1:

<!-- Both of these libs must be here in order to get performant behavior out of Jaxb by default. 
--> 
<dependency> 
     <groupId>com.sun.xml.fastinfoset</groupId> 
     <artifactId>FastInfoset</artifactId> 
     <version>1.2.13</version> 
     <scope>compile</scope> 
</dependency> 
<dependency> <!-- This artifactId also exists under javax.xml.bind but it appears that nobody uses that one... --> 
    <groupId>javax.xml</groupId> 
    <artifactId>jaxb-impl</artifactId> 
    <version>2.1</version> 
    <scope>runtime</scope> 
</dependency> 
<!-- End: Both of these libs... --> 
:このFastinfosetライブラリとパフォーマンスが向上しJAXBのバージョンを使用するJAXB-IMPLで異なるJAXB実装

プルに全体のアプリを経由スワップシンプルなアプローチ

これは、残りのコードで使用されるjaxbバージョンを更新する副作用を伴います。場合によっては、望ましくない場合もあります。たとえば、さまざまなアプリケーションで使用する必要がある共有ライブラリを作成している場合、共有コンポーネントを取得するときにこの機能を変更するのは失礼です。

ソリューションオプション2:文字列がすでに日陰に

  • 使用「のmaven-シェードプラグイン」(実装がより複雑に)抑留されていることを信頼にそれをだましてJVMのJAXB実装と性能ハックを使用しますFastinfosetライブラリのクラスを再パッケージ化します。結果は、論理なしのコンポーネントでなければなりません。これはオプションで、Fastinfosetコーデックコンポーネントを使用している人が、コーデックライブラリによって引き継がれた推移的な依存関係のためにクラスパスの衝突を起こさないようにするためのものです。
  • Fastinfosetペイロードをエンコードおよびデコードする簡単なAPIを提供するmy-fastinfoset-codecライブラリを作成します(引数にはInputStreamとOutputStream、デコーダの戻り型にはXMLStreamReaderを使用することを検討してください)。再パッケージ化されたFastinfosetライブラリに依存関係を追加します。 Eclipseを使用している場合、m2eの "Workspace Resolution"が有効になっている場合、陰影付ライブラリーではうまく扱えないので、コーデックプロジェクトでは無効にしてください。
  • リパッケージされたFastinfosetライブラリの "StAXManager"を拡張するクラスをmy-fastinfoset-codecに追加します。このクラスは、与えられたXMLStreamReaderが既にNSとタグの名前文字列を保持していることをjaxbに通知するプロパティの設定を容易にする必要があります。例は以下の通りです:
 
    package myrepackagedfastinfosetclassespackageprefix.shaded.com.sun.xml.fastinfoset.stax; 
    import myrepackagedfastinfosetclassespackageprefix.shaded.com.sun.xml.fastinfoset.stax.StAXManager; 
    public class JaxbStringInternSuppressionStaxManager extends StAXManager { 
     public JaxbStringInternSuppressionStaxManager() { 
      // Add to the allowable list of feature names so that the user may set these "StAXInputFactory" properties 
      super.features.put("org.codehaus.stax2.internNames", null); 
      super.features.put("org.codehaus.stax2.internNsUris", null); 
     } 

     /** 
     * This is an optimization. The FastInfoset libraries already intern strings and the JVM's jaxb implementation by default 
     * unnecessarily repeats that work. This is true at least for the 64 bit version of jdk1.8.0_121. 
     * 
     * The way that this workaround works is by piggybacking on a Jaxb optimization for the Woodstox parser. When we set 
     * these properties it tells jaxb that Woodstox has already interned the strings which causes it to disable its 
     * string interning. 
     * 
     * We did explore the cleaner option of pulling in the Maven "javax.xml:jaxb-impl" artifact as a dependency instead of using 
     * the JVM's jaxb library. That external jaxb library when used with the FastInfoset library does perform substantially better 
     * than the JVM's but isn't 100% as fast as the JVM's with interning disabled. The key reason that we quit exploring that solution 
     * is that when you repackage (via maven-shade-plugin) the jaxb libraries they no longer work with our standard jaxb binding 
     * maven components due to statements like "if (instanceof my_repackaging_project.shaded.XMLElement)" 
     * used during the data mapping process. 
     */ 
     public JaxbStringInternSuppressionStaxManager enableTrickToStopJaxbFromInterningStrings() { 
      super.setProperty("org.codehaus.stax2.internNames", true); 
      super.setProperty("org.codehaus.stax2.internNsUris", true); 
      return this; 
     } 
    } 

ソリューションオプション3:OracleとJVMのサポート契約を結んでいる十分な人々がある種の非内部fastinfosetのサポートを求めてチケットを上げます。

このFastinfoset実装がインターン・ストリングに設定されていることを、指定されたXMLStreamReaderから判断するために、OracleがJVM提供のjaxb実装を教えることはかなり簡単です。うちパンなかった

ソリューション可能性:一つは、カスタム接頭辞パッケージ名を持つ新しいjarファイルを作成するには、「Mavenのシェード - プラグイン」または類似を使用することができます

上記溶液1から2つのjarファイルを再パッケージします。これは、いくつかの手抜きの後、これらのライブラリで動作しました。しかし、最終的な結果は、再パッケージ化されたjaxbライブラリが、jaxb-RIで生成されたOXMオブジェクトに新しい陰影付きパッケージ名の注釈を付けることを望んでいたことです。私の再パッケージ化されたソリューションはどのデータも自分のオブジェクトにマッピングしないように標準的な方法で構築されました。私は、OXMバインディングライブラリが再パッケージ化されたjaxbライブラリを使用するよう指示するつもりはなく、これらのアノテーションに使用するパッケージを変更しないように、より慎重に再パッケージングする方法を探求するのに十分なこのアプローチが好きでした。

私は探検しませんでした

ソリューションオプション:「.Internalインタ」

を持っているJVMのfastinfosetクラスを使用します彼らのパッケージ名で。それらはJVMに付属のjaxb実装ではうまくいくはずですが、内部APIを使用してサポートコストに "将来の私"を晒すことを拒否します。

関連する問題