String -> byte[] 変換を集中的に使用するコードを継承し、その逆も同様です。基本的に、Java オブジェクトは、その構成部分を文字列に変換する方法を知っており、文字列はバイト [] に変換されます。次に、このバイト配列は、JNI を介して C++ コードに渡されます。C++ コードは、byte[] を C++ std::strings に再構成し、それらを使用して、Java オブジェクトをミラーリングする C++ オブジェクトをブートストラップします。もう少し続きがありますが、これはこのコードがどのように機能するかの概要です。通信は双方向でこのように機能するため、C++ -> Java 遷移は、前述の Java -> C++ 遷移のミラー イメージです。
このコードの一部 (String から byte[] への実際の変換) が、予期せずプロファイラーに表示され、大量の CPU を消費しています。確かに、大量のデータが転送されていますが、これは予想外のボトルネックです。
コードの基本的な概要は次のとおりです。
public void convertToByteArray(String convert_me, ByteArrayOutputStream stream)
{
stream.write(convert_me.getBytes());
}
機能にはもう少しありますが、それほど多くはありません。上記の関数は、文字列/文字列化されたオブジェクトごとに 1 回呼び出され、すべての構成要素が ByteArrayOutputStream に書き込まれた後、ByteArrayOutputStream は byte[] に変換されます。呼び出しを抽出して上記をよりプロファイラーに適したバージョンに分解するとconvert_me.getBytes()
、この関数の時間の 90% 以上が getBytes() 呼び出しに費やされていることがわかります。
getBytes() 呼び出しのパフォーマンスを改善する方法はありますか、または同じ変換を達成するための別の潜在的に高速な方法はありますか?
変換されるオブジェクトの数は非常に多くなります。本番データの小さなサブセットのみを使用しているプロファイリングの実行では、1,000 万以上の上記の変換関数の呼び出しが見られます。
プロジェクトの本番環境へのリリースが近づいているため、現時点では実行できないいくつかの回避策があります。
- シリアライゼーション インターフェイスを書き直して、JNI レイヤー全体で String オブジェクトを渡すだけにします。これは (私にとって) 状況を改善する明白な方法ですが、シリアライゼーション レイヤーの大幅な再設計が必要になります。今週初めに UAT に移行するという事実を考えると、この種の複雑な変更を行うには遅すぎます。これは次のリリースに向けた私の最優先事項なので、完了します。ただし、それまでは回避策が必要ですが、これまでのところコードは機能しており、何年も使用されており、ほとんどの問題は解決しています。まぁ、演出は別として。
- JVM (現在は 1.5) を変更することもできません。残念ながら、これはクライアントのマシンにインストールされているデフォルトの JVM であり、1.6 への更新 (この場合は高速である場合とそうでない場合があります) は残念ながら不可能です。大規模な組織で働いたことのある人なら、おそらくその理由を理解しているでしょう...
- これに加えて、すでにメモリの制約に直面しているため、少なくともより大きな文字列とそのバイト配列表現をキャッシュしようとすると、洗練されたソリューションになる可能性がありますが、解決するよりも多くの問題が発生する可能性があります。