torutkのブログ

ソフトウェア・エンジニアのブログ

JavaOne 2013 SF(09-26)

(超暫定、後ほど書く)
次のセッションを聴講しました。

  • Advanced JVM Tuning(11:00-12:00)
  • Save Scarce Resources by Managing Terabytes of Objects Off-Heap or Even on Disk (12:30-13:30)
  • Mixed-Language Development Leveraging Native Code from Java (14:00-15:00)
  • Java Memory Hogs (15:30-16:30)

夜は日本から参加したメンバー有志による蟹パーティです。

JavaOne Community Keynote

自主休講しました。動画が公開されています。

Advanced JVM Tuning【CON4540】

講師はDavid Keenan氏(Twitter

立ち見が出ていたセッションです。また、早口! これは厳しそうです。
mpstatの話から入っていた(?)。

Latency、スループット、フットプリントの三角関係があり、スループットを高めるとフットプリントが大きくなり、Latencyが低下します。また、Latencyを小さくするとフットプリントが小さくなり、スループットが低下します。このように、性能の項目間にはトレードオフの関係が生じます。

正しいメトリクスを選ぶのが大事です。ユーザーに影響するものは何かを見極めます。
スループットのメトリクスには

Latencyのメトリクスには

フットプリントのメトリクスには

  • Full GC直後のヒープサイズ
  • ネイティブプロセスのサイズ

があります。

有効データサイズは、Full GC直後のデータサイズを継続的に追跡することで導き出します。
定常的に生きているデータの2倍から出発するとよいとのことです。
CMSでは、プロモーション頻度が大きければOld領域を増やします。
youngサイズは最初young=oldで開始し、アロケーションレートが大きいならyoungを増やして行きます(おおむねOldの2-3倍まで)。

ケーススタディとして、エンタープライズアプリケーション、3.5GB、ライブデータ4GB、アロケート頻度大というものを検討します。
推奨ヒープサイズは、-Xms16g -Xmx16g -Xmn8g

スループット向上のGCは、-XX:+UseParallelOldGC
応答時間向上のGCは、古い技術のCMSか今のG1GCか

GCログを観察し、アロケーションレート、プロモーションレートを計算します。
GCログを観察する場合、推奨オプションは

  • -XX:+PrintGCDateStamps
  • -XX:+PrintGCDetails
  • -XX:+PrintGCTimeStamps
  • -Xloggc:/tmp/file

必要に応じて役立つオプションは

  • -XX:+PrintHeapAtGC
  • -XX:+PrintTenuringDistribution
  • -XX:+PrintGCApplicationStoppedTime
  • -XX:+PrintReferenceGC

アロケーションレートは、GCログからGC[ParNew: を探し、前後のメモリサイズを引き算してアロケーション量を計算し、それを前回のGC[ParNew:発生時刻と今回のGC[ParNew:発生時刻の差で割ってあげると出ます。

プロモーションレートは、今回GC[ParNew: のOld領域サイズと前回GC[ParNew:のOld領域サイズを引き算して、それを時刻差で割って算出します。

Latencyのチューニングは、
CMSならば

  • -XX:+CMSScavengeBeforeRemark
  • -XX:+ParallelRefProcEnabled
  • -XX:CMSInitiatingOccupancyFraction=70

あたりがお勧めです。

アロケーションレートが高ければYoung領域を増やします。同様にプロモーションレートが高ければYoung領域を増やします。それでもまだプロモーションレートが高ければOld領域を増やします。

G1GCならば、-XX:MaxGCPauseMillis=100あたりから開始し、この値を調整していきます。

スループットのチューニングは、

ParallelOldGCならば、Old領域をライブデータ量の2〜4倍とし、Young領域はヒープの3/4とし、-XX:+AggressiveOpts -XX:+TieredCompilationを入れてみるとか、サバイバ領域のサイズを自動任せにせず指定するといった方法となります。

G1GCは、ParallelOldGCと同じです。

CMSならば、-XX:+UseParNewGCとし、プロモーションが発生しないようヒープを設定し、アプリケーション設計上でもステートフルとステートレスを分けるようにしてチューニングしやすくします。

フットプリントのチューニングは、

ParallelOldGCならば、ライブデータ量の2倍をOld領域とし、Youg領域はOld領域の1/2とします。

G1GCならば、ライブデータ量の3倍をヒープとし、Young領域の調整はしないでG1GCに任せます。GCのオーバーヘッドを減らすためPause目標値を大きくします。-XX:MaxGCPauseMillis

CMSならば、Old領域はライブデータ量の2倍とし、Youg領域はOld領域の1/2とします。

一般的なパフォーマンス問題

パーマネント領域はフルGCのときに回収されます。
エンタープライズアプリケーションはコード量が大きいので多くパーマネント領域を確保します。推奨は次です。

  • XX:PermSize=256m -XX:MaxPermSize=256m

コードキャッシュサイズはデフォルト64MB、TieredCompilationが有効のときは96MBです。
TieredCompilationが無効のときは

  • -XX:InitialCodeCacheSize=128m -XX:ReservedCodeCacheSize=128m

TieredCompilationが有効のときは

  • -XX:InitialCodeCacheSize=256m -XX:ReservedCodeCacheSize=256m

TwitterサーバーはJavaScalaで記述され、HotSpot VM上で動いています。
特にLatencyが厳しいです。

Save Scarce Resources by Managing Terabytes of Objects Off-Heap or Even on Disk 【CON7793】

講師はHarvey Raja氏(Oracle)、Chris Neal氏(Pegasus Solutions)。

何を言いたいセッションだったのかよく分かりませんでした。このセッションは、Oracleの商用ミドルウェアOracle Coherenceを使うといいよという内容に思われます。後日公開されたスライドを見ましたが、うーん、読解できませんでした。

Mixed-Language Development Leveraging Native Code from Java【CON3408】

講師は、Darryl Gove氏(Oracle)。

パフォーマンスを理由にネイティブコードを呼び出すのは要注意です。必ずしも速くはなりません。

JNI

native宣言したメソッドは、loadLibraryでロードしたネイティブコードを呼び出します。
loadLibraryで指定した名前は、OS依存のファイル名に自動で変換されます。UNIX系ならlib+名前.so、Windowsなら名前.dllです。
デフォルトサーチパス、LD_LIBRARY_PATH、-Djava.library.pathで指定したパスから検索されます。

JNIのCヘッダーファイルは、native宣言したJavaクラスをjavacでコンパイルした後、javahコマンドで生成します。

ネイティブコードをコンパイルするときは、ライブラリとして生成し、PIC(Position Independend Code)を指定します。Solaris Cコンパイラなら、-G -Kpic -g -O -I... といったオプションになります。

Solaris環境でのネイティブコードのデバッグは、デバッガdbxを使い、性能解析にはcollectとanalyzeを使います。これらはOracle Studio(Solaris環境でのC/C++開発環境)に付属のツールと思われます。

JNI以外の方法

JNA、JNRがあります。

Java Memory Hogs【CON4695】

講師は、Nathan Reynolds氏(Oracle)です。

満席です。
氏は、PSRチーム(Performance, Scalability, Reliability)に属しています。

一般的にJavaC++の2倍のメモリを使います。
ヒープダンプによってアプリケーションの使用するメモリ解析ができます。
メモリを減らすとGC時間が減るので、平均応答時間が早くなります。

ツール紹介:JOverflow JavaOne 2012 SFのCON2769を参照、ヒープダンプ解析ツールです。

Stringは1/4のヒープを占めるインスタンスです。
数値を文字列にエンコードしてはなりません、ヒープの無駄遣いになります。
byte[]を使う場合、I/Oバッファとして使用するならDirectByteBufferを推奨します。
ヒープの20%はコレクションが占めます。
素数が4以下のコレクションは、配列にするか要素をフィールドにしたクラスにするのがメモリ的には効率がよいです。
ArrayListは大抵属性の半分以上が未使用なのでもったいないです。
OpenJDKではHashMapの効率化を実装しています。
Java SE 7u40とJava SE 8ではConcurrentHashMapの効率化を実装しています。

幾つかの事例を見ていると、いまだにHashtableを使っている人がいます!

Collectionの大半は要素数が少ないものです。

すごい事例としては、344個もフィールドのあるクラスを見たことがあります。

メモリ最適化としてすべきこと

  1. Stringのコピー抑止
  2. プリミティブ配列のコピー抑止
  3. オブジェクトヘッダーの圧縮

お昼

JavaOne配給食を食べました。


日本からのJavaOne参加者による蟹パーティです。
場所は、オーシャンビーチそばのレストランです。Powell St.駅からMuni MetroのNラインに乗って行きます。30分ちょっと乗ってオーシャンビーチの手間で降りますが、少し時間が余ったので、オーシャンビーチにいって時間をつぶしてからレストランに向かいました。

オーシャンビーチでは、大山さん、櫻庭さん、小出さんたちと会いました。皆さん一眼レフカメラであれこれ撮っていました。

1時間ほどビーチに滞在し、サンセットを迎えてからレストランへ移動しました。

蟹はオイリーでスパイシーで濃い味付けでした。一人105ドルの夕食です。

レストランの予約に会計処理にと幹事をしていただいた山本裕介さん、ありがとうございました。楽しくおいしかったです。
カード決済なので現金を懐に抱えて持ちかえったそうです。翌日ATMで入金したそうです。

会場を22:00過ぎころ撤収し、Muni Metro NラインでPowell St.駅へ戻り、23:17のBARTに乗り換え、24:00にPleasant Hill駅を下車、ちょっとおっかなびっくりホテルまで戻りました。

いよいよ明日(もう今日ですが)はチェックアウトと帰国の日です。