「Java パフォーマンス」を読みました
今更感はありますが、次の泥沼にはまる前に基本に立ち返ってみようとJavaの本を一冊読んでみました。
- 作者: Scott Oaks,アクロクエストテクノロジー株式会社(監訳),寺田佳央(監訳),牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/04/11
- メディア: 大型本
- この商品を含むブログ (3件) を見る
著者は、15年間サンマイクロシステムズとオラクルにおいてJavaのパフォーマンスに携わってきた方で、 なかなか読み応えのある内容。 きちんとJavaの流行を追っかけてる人にとっては当たり前のことなのかもしれませんが、Java6の時代でほぼ止まっている私のような 人間にとって、改めて勉強になることが多い本でした。
第一章 イントロダクション
この本の方向性がかかれています。パフォーマンスを引き出す為には科学者と芸術家の両方のセンスでアプローチを行うことが必要とのこと。
第二章 パフォーマンステストのアプローチ
パフォーマンステストを行う際の手法や考え方の概論。パフォーマンスエンジニアは、可能な限り自動化してデータを収集・測定し、得られた結果の不確かさについて理解し、どの部分の改善に時間を費やすかを判断するかが大切とのこと。
第三章 Javaパフォーマンスのツールボックス
OSやJDKに付属している主要なツールの説明と使い方の解説。とにかくデータを集めることが大切とのこと。
第四章 JITコンパイラのしくみ
中間コードに過ぎないJavaバイトコードが、どうして今のようなパフォーマンスを生み出せるのか、 その源泉とでも呼ぶべきjust-in-timeコンパイラの動きを解説。コンパイルモードやインライン化など、いままで間違って覚えていたことがいろいろと発覚。
第五章 ガベージコレクションの基礎
JITと並んでJavaのパフォーマンスに影響を与える存在。Java7,Java8で用意されているシリアル, スループット(パラレル), CMS, G1の4タイプのGCの概要を解説。最大Heapサイズを適切な値に設定することと、GCのログを取る事が重要とのこと。
第六章 ガベージコレクションのアルゴリズム
スループット,CMS,G1のアルゴリズムの細かいところと、チューニングのやり方を解説。今までG1の 仕組みをよく知らなかったのですが、4GB以上のメモリと、CPUに余裕があるならかなり有効な方式のようです。
第七章 ヒープのベストプラクティス
適切なメモリ管理を行うための方法の解説。 できるだけオブジェクトを抱え込まないようにしてGCの発生を抑える事が、 パフォーマンスをよくすることにつながるそうです。 Javaのヒープからのメモリ割り当てコストは小さいため、 allocateとinitializeを区別して、initializeに時間がかかるものだけをプールしたりキャッシュしたりするように、との部分は目から鱗でした。
第八章 ネイティブメモリのベストプラクティス
OSの管理するメモリをどのように効率的に使えるようにするかという解説。あまり細かい設定はできないが、どのJVMがどのように Nativeなメモリを利用しているかを知る事は大切との事。
第九章 スレッドと同期のパフォーマンス
マルチスレッドと同期処理によるパフォーマンスの解説。パフォーマンスが出ない時に、 スレッドプールの最大数を増やすのは間違いであることがほとんど。スレッド数が増えればその分だけ同期処理のオーバーヘッドが必要となるため、並列実行が可能な処理において、実行するスレッド数を増やしてもリニアに効率は上がらないことを心得ておくのが大切とのこと。 分割統治に適したForkJoinPoolの利点をはじめて理解。
第十章 Java EEのパフォーマンス
Webコンテナである Java EEのパフォーマンスの解説。むやみにセッションに値を保持しないことや、スレッドプールの利用による効率化。 また、XMLやJSONでの外部とのやりとりのあれこれの解説。オブジェクトのシリアライズ/デシリアライズの効率化の解説。 シリアライズを適切に最適化するのは骨の折れる作業。transientとObjectOutputStream#defaultWriteObject()で少しでもシンプルにすること。 ネットワーク経由でのやりとりでは、データ量をできるだけ減らし、どのような環境でもアプリが正しく機能するようにするのが大切とのこと。
第十一章 データベースのベストプラクティス
データベースを扱うならば、データベースのチューニングやプログラミングを学ぶべきだが、Java側のプログラムでも考えるべきことはある。 JDBCはnativeのtype2とpure javaのtype4が主に使われており、パフォーマンス的にはどちらも変わらない。繰り返し実行する ものはプリペアドステートメントにし、ステートメントプールを利用すること。バッチでクエリを実行する回数を減らすこと。 JPAのようなORMも設定によってパフォーマンスが大きくかわる。といった内容。JDBCは普段からよく使っているのと、 ORMはまともに触った事がないのとで、この章は半分斜め読みでした。
第十二章 Java SEのAPIのパフォーマンス
Java SE APIでパフォーマンスをよくするための解説。バッファリングされた入出力を適切に使うこと。Java7で改善されたとはいえ、 クラスローダーによるロードはボトルネックとなりうること。Javaが遅いのは過去の話しであり、JNIの使用ははOS固有の機能を呼び出すためだけとし、 パフォーマンス向上の目的で使わないこと。 例外の発生やtry/catchブロックが高コストだったのは遠い過去のこと。ただし、例外オブジェクトをnew している場合はコールスタックが深くなればなるほどコストが高くなることに注意すること。コレクションに関しては防衛的プログラミングがよい。Java7以降ではConcurentHashMapをHashMapのかわりに使用してもそれほどパフォーマンスが落ちる事は無い。無名クラスとラムダでは速度に差はなく、クラスローダーの動作が必要な関係で無名クラスの分が悪い。ラムダとStreamを強く推奨、つまりさっさとJava8にしろということのようです。
そろそろJavaから離れて何か他の言語でWeb屋さんとしてデビューしようと思っていたのですが、なんだかJava8がものすごくよさそうだと再認識しました。
とりあえずなにかフレームワークを使いこなせるよう精進してみたいと思います。