Java EEアプリケーションサーバの開発現場で見たJava SEの実際

Java EEアプリケーションサーバの開発現場で見た
Java SEの実際
2015/04/08
日本電気株式会社
翁 信之介
目次
▌はじめに
▌Java SEバージョンアップの経験談
▌Java SE 8 Metaspace領域の解析
▌NECの取組み
▌おわりに
本資料で使用するシステム名、製品名は、それぞれ各社の商標、または登録商標です。
なお、本文中ではTM、®、© マークを省略している箇所があります。
Page 2
© NEC Corporation 2015
はじめに
Java EEの下層に位置するJava SEはOSと同様に品質が重要
▌Java EEアプリケーションサーバにとってJava SEは肝であり、その品質がシステム全体に与え
る影響は大きい
機能、性能、互換性、障害解析ツール、セキュリティ問題、etc.
Servlet / JSP
JFS
Java EE
EJB
JAX-RS
JSON
Driver
JDBC
Java SE
StAX
Batch
JMS
JTA
CORBA
RMI-IIOP
JAAS
JPA
Directory SV XML Parser
JNDI
JAXP
JAX-WS
JAXB
JAF
Agent
JMX
SAAJ
Java VM
OS
Page 4
© NEC Corporation 2015
Solaris
Linux
Windows
HP-UX
商用ベンダーに求められる品質
▌お客様からはOSSのアプリケーションサーバにはない、商用ベンダーならではの厳格な実装品
質と手厚いサポートの期待あり
旧互換性の維持
特性
副特性
機能適合性
機能完全性、機能正確性、機能適切性
• 異常系動作の結果やメッセージの維持
性能効率性
時間効率性、資源効率性、容量満足性
• 永年サポート
互換性
共存性、相互運用性
使用性
適切度認識性、習得性、運用操作性、ユーザエラー防
止性、ユーザインタフェース快美性、アクセシビリティ
• 動作不正、性能劣化
信頼性
成熟性、可用性、障害許容性(耐故障性)、回復性
• Java EE仕様が重厚になっても全パス試験に
よる保証は、お客様にとって当たり前品質
セキュリティ
機密性、インテグリティ、否認防止性、責任追跡性、真
正性
保守性
モジュール性、再利用性、解析性、修正性、試験性
移植性
適応性、設置性、置換性
• 下層SWの振る舞い変更をAPサーバで回避
ex.) Java SEの仕様変更
(EJB 1.1 Container on JDK 1.2.2 ;-)
決して許されないデグレード
セキュリティ脆弱性問題の迅速な対応
• 過去の製品に同梱した古いOSSに含まれた
セキュリティ問題に対するパッチ提供
ex.) Struts 1、OpenSSL 0.9.x
Page 5
© NEC Corporation 2015
ISO/IEC 25010 システム及びソフトウェア製品の品質要求及び評価(SQuaRE)
− システム及びソフトウェア品質モデル
商用ベンダーの悩み
動作不正
製品不具合、業務アプリケーションのバグ
連携製品の問題、操作ミス ・・・
問合せ受付
ログ解析や運用状況のヒアリング等からの事象の分析
ソースコード調査
リリースメモ、JavaDocやマニュアルの確認
バグデータベースの検索
Webに公開されている一般情報
実機での再現検証 ・・・
お客様は即時回答を切望
迅速、正確、丁寧な対応が顧客満足度に直結
お客様から見るとJava EEの下位層(Java SE、OS)も含めて「アプリケーションサーバ」
Page 6
© NEC Corporation 2015
Java SE 8 サポートを急ぐ理由
▌前回のJava SE 6 EOLでは過去に例をみない大きな話題へと発展
▌お客様のセキュリティ問題に対する関心が急激に高くなったことが背景にあり
Java SEにセキュリティ問題がまだ潜在するにも
関わらずEOLが目前
行政からの注意喚起を基点に多くの業種で
Java SEのバージョンアップ要求が拡散。
メディアでも大きく取り上げられ、短期間に
問合せが殺到
Java SE 5以前で稼働中のシステムにも
最新化検討へ波及。ますます大きな騒ぎに
製品供給者としての社会的責任を果たすべく、
迅速な最新 Java SE 対応を推進
 直前に迫るJava SE 7 EOLについては
2015/3/3 内閣官房情報セキュリティセンター
ウェブサイト等の利用者に使用を求めているソフトウェアのサポート終了に伴う対応
について(注意喚起)
http://www.nisc.go.jp/active/general/pdf/soft_150303.pdf
Page 7
© NEC Corporation 2015
内閣官房情報セキュリティセンター (2014/7/17)
Java SE 6のサポート有効期間の満了に係る対応について(注意喚起) 一部抜粋
http://www.nisc.go.jp/active/general/pdf/javasupport_press_120717.pdf
Java SE バージョンアップの経験談
開発現場で遭遇した事象
▌Java EEアプリケーションサーバ開発時の直面した、様々なアクシデントをご紹介
Java SE 8で新規に発生
•Lambdaを使用したアプリケーションが配備できない
•wsimportコマンド実行時にエラーが発生
メジャーバージョンアップで動作が変更
•クラスローダーでデッドロック
新しいUpdateバージョンで動作が変更
•カスタムORBの初期化に失敗
•ロガーのインスタンスがすり替わる
•java.util.Logger#getLogger()でnullを返却
•添付ファイル付きSOAPメッセージで例外
過去から長期にわたって不具合が修正されず
•AWTでjava.lang.UnsatisfiedLinkErrorが発生
Page 9
© NEC Corporation 2015
1. Lambdaを使用したアプリケーションが配備できない
Java SE 8で新規に発生
▌事象: Lambdaを使用したアプリケーションを配備すると例外が発生
2015-03-19 19:20:43,025 ERROR
DEPLOY
- Exception while visiting
sample/HelloBean.class of size 1468 [deployment-jar-scanner]
java.lang.ArrayIndexOutOfBoundsException: 52264
▌原因: 配備時にバイトコード操作ライブラリ
「ASM」がLambdaを使用したクラスファイルの
解析に失敗するため
▼コンスタントプールの型
Lambdaではクラスファイルのコンスタントプール
にJava SE 7で拡張された InvokeDynamic、
MethodHandle、MethodTypeが出現
コンスタントプールの各エントリについて、タグバ
イトで型を読み、その先にある型ごとに既定され
た長さのデータを読むが、未定義な型によりデー
タを誤って読んでしまう
03 00 00 00 0A
タグバイト データ
Page 10
© NEC Corporation 2015
Integer(0x03) の
42(0x0000000A)
12 00 00 00 26
タグバイト データ
?
1. Lambdaを使用したアプリケーションが配備できない (cont.)
▌対処: ASMのバージョンアップ
クラスファイルの拡張自体はJava SE 7で行なわれたが、
Javaプログラムから生成されることはなかったため顕在化
しなかったと考えられる。
別のバイトコード操作ライブラリを利用したアプリケーション
も注意が必要 (右表)
▼OSSのバイトコード操作ライブラリ
ライブラリ
Java SE 8対応
バージョン
OW2 ASM
5.0
Javassist
3.19.0-GA
(JBossのサブプロジェクト)
Apache Commons BCEL
6.0 RC
▼Apache Commons BCEL 5.2の実行結果
Exception in thread "main" org.apache.bcel.classfile.ClassFormatException: Invalid byte tag in
constant pool: 18
at org.apache.bcel.classfile.Constant.readConstant(Constant.java:146)
at org.apache.bcel.classfile.ConstantPool.<init>(ConstantPool.java:67)
at org.apache.bcel.classfile.ClassParser.readConstantPool(ClassParser.java:222)
at org.apache.bcel.classfile.ClassParser.parse(ClassParser.java:136)
at Main.main(Main.java:6)
18(InvokeDynamic)が不正なバイトタグとして例外が発生している。
言語仕様が拡張されると思いもよらぬところで非互換が発生する
Page 11
© NEC Corporation 2015
2. wsimportコマンド実行時にエラーが発生
Java SE 8で新規に発生
▌事象: Java SE 8でJDK付属のwsimportコマンドを実行した際に、java.lang.AssertionErrorエ
ラーが発生
このコマンドの延長で実行するJAXBのバインディングコンパイラ(xjc)において外部スキーマ(インク
ルード/インポートしたxsdファイル)を参照するが、そこで処理に失敗
▌原因
org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory#newSchema(URL)でxsdファイル
へのアクセスに失敗
Java SE 8に同梱されているJAXPのバージョンが1.5に更新。 JAXP1.5では外部スキーマ参照時に
セキュリティチェックが行われるように変更され、さらに、デフォルト設定では外部スキーマへのアクセ
スが不可になっていた。
(※)wsimportとは、WSDLファイルからWebサービスの動作に必要なクラスを生成するためのツール
Page 12
© NEC Corporation 2015
2. wsimportコマンド実行時にエラーが発生 (cont.)
▌対処
一般的には下記のシステムプロパティを設定することで回避可能
(GlassFish 4.1では、domain.xmlにデフォルトで設定済)
javax.xml.accessExternalSchema=all
file、http、allなど、アクセス権を与えるプロトコルを指定
XMLSchemaFactoryを使用してXML解析処理を実装している場合、setProperty()メソッドでアクセス
権限を付与することでも対処可能
String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"
//JAXPのXMLSchemaFactoryを取得
SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false);
//外部スキーマへのアクセス権限を付与
sf.setProperty(ACCESS_EXTERNAL_SCHEMA,"all");
Schema schema = sf.newSchema(source);
Page 13
© NEC Corporation 2015
2. wsimportコマンド実行時にエラーが発生 (cont.)
▌その他
XMLSchemaFactoryクラスを使用しており、かつ外部スキーマ参照があるXML解析を行っていると同
様の問題が発生する可能性あり
JAXPの仕様変更のようにデフォルトの挙動が変わることもあるので、バージョンアップ時の更新内容
をキャッチアップすることは重要
Page 14
© NEC Corporation 2015
メジャーバージョンアップで動作が変更
3. クラスローダでデッドロック
▌事象: アプリケーション実行中に不定期に
デッドロックが発生
▌原因: 階層構造のクラスローダで逆方向の
ロックが発生したため
Java SE 6までは、階層構造のクラスローダで
子から親の順番でロックするのが鉄則
▼動作例
a. 親クラスローダでクラスロード中にパーミッション
チェックを実行
(例えばaccessClassInPackageで権限が必要な“sun.”から始
まるパッケージのクラスのロード時)
b. sun.security.provider.PolicyFile#addPermissions()で
コンテキストクラスローダを用いてクラスロード。し
かし、コンテキストクラスローダは子クラスローダで
あり、逆順のロックでデッドロックに至る
Page 15
© NEC Corporation 2015
▼動作例におけるコールスタック
Java stack information for the threads listed above:
===================================================
"Thread-0":
at java.lang.ClassLoader.loadClass(ClassLoader.java:404)
- waiting to lock <0x099778f8> (a ParentClassLoader)
4
at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
- locked <0x0998b920> (a ChildClassLoader) 2
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sample.Main$Loader.run(Main.java:61)
"main":
3
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at sun.security.provider.PolicyFile.addPermissions
(PolicyFile.java:1357)
(中略)
at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
- locked <0x099778f8> (a ParentClassLoader)
1
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
1
ロック
コンテキストクラス
ローダに設定
ロック
2
main
3
親クラスローダ
ロック待ち
子クラスローダ
ロック待ち
Thread-0
4
3. クラスローダでデッドロック (cont.)
▌対処: クラスローダのデッドロックが解消された Java SE 7以降を使用
それでもまだ問題は解消しない・・・
▌原因: 自作クラスローダの処置が未実施
▌対処: パラレル対応クラスローダに修正
クラスロードをスレッドセーフにすることも必要だが、クラスローダのクラスの静的初期化子(staticイ
ニシャライザ)でjava.lang.ClassLoader#registerAsParallelCapable()メソッドを呼び出すことが重要
public class MyClassLoader extedns ClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
...
http://www.oracle.com/technetwork/jp/articles/java/classloaderproposal-428895-ja.html
Page 16
© NEC Corporation 2015
新しいUpdateバージョンで動作が変更
4. カスタムORBの初期化に失敗
▌事象: Java SE 7u55にアップデートするとカスタムORBを利用したアプリケーションでの
org.omg.ORB#init()メソッド呼び出しに失敗する
Exception in thread "main" org.omg.CORBA.INITIALIZE: can't instantiate default ORB
implementation jp.co.nec.orb.OSPORBSingleton vmcid: 0x0 minor code: 0 completed: No
at org.omg.CORBA.ORB.create_impl_with_systemclassloader(ORB.java:309)
at org.omg.CORBA.ORB.init(ORB.java:294)
▌原因: システムプロパティ
「org.omg.CORBA.ORBSingletonClass」で
指定したORBSingletonクラスをロードする
クラスローダの変更
7u51以前: スレッドにコンテキストクラスローダが
設定されていれば「コンテキストクラスローダ」。
そうでなければ「システムクラスローダ」
7u55: システムクラスローダのみ
8u5、6u75、5u65も同様に動作変更
Page 17
© NEC Corporation 2015
クラスローダ階層(一部省略)
システムクラスローダ
APサーバのライブラリ用
クラスローダ
ORBSingleton
アプリケーションクラスローダ
アプリケーションクラスローダ
アプリケーションクラスローダ
ORB#init()実行時に
コンテキストクラスロー
ダへ設定したライブラ
リ用クラスローダに
ORBSingletonクラス
をロードさせていた
4. カスタムORBの初期化に失敗 (cont.)
JDK-8042789
▌リリースノートで示された対処:
カスタムORBのライブラリJarをシステムクラスローダでロードするようにライブラリ配置を変更
システムクラスローダ
ORBSingleton
APサーバのライブラリ用
クラスローダ
アプリケーションクラスローダ
アプリケーションクラスローダ
アプリケーションクラスローダ
⇒ 納得いかずJava Bug Databaseに報告
バグとして認められ、製品としては修正された
Updateバージョンの使用を告知
• 元に戻されたバージョン: 8u20、7u65、6u85、5u75
• Java SE 9ではこの動作が正式なものになる模様 →
Page 18
© NEC Corporation 2015
バグとして修正
ただし
Java SE 9は
Won't Fix
5. ロガーのインスタンスがすり替わる
新しいUpdateバージョンで動作が変更
JDK-8024827
▌事象: Java SEを7u21以前から7u25に更新すると、あるタイミングでLogger#getLogger()
呼び出しで取得したLoggerが別インスタンスを返却するようになった。これにより、以前のイン
スタンスで設定したログレベルなどの変更が無効になる。
▼アプリケーションサーバ起動中
Logger.getLogger("foo") -> java.util.logging.Logger@148662
▼起動後
Logger.getLogger("foo") -> java.util.logging.Logger@1829e6f
▌原因: セキュリティマネージャー有効時、sun.awt.AppContextクラスのロード前後でロガー名を
管理する空間が別になったため
Appletの独立性を高める変更に影響
sun.awt.AppContextクラスはGUIを使用しなくとも、ImageIOなどを使用するとロードされる
Logger before = Logger.getLogger("test");
Class.forName("sun.awt.AppContext");
Logger after = Logger.getLogger("test");
System.out.printf("before: %s, after: %s", before, after);
Page 19
© NEC Corporation 2015
5. ロガーのインスタンスがすり替わる (cont.)
▌対処: 起動処理の早い段階で sun.awt.AppContext クラスロード処理を追加
他にも、システムプロパティ「javaplugin.version」あるいは「javawebstart.version」が設定されていれ
ば発生しないことが判明。ただし、明示的に設定することに対する影響度は不明
または、Java SE 7u60で改修されたため、このUpdateバージョン以降を使用する
Page 20
© NEC Corporation 2015
6. java.util.Logger#getLogger()でnullを返却
新しいUpdateバージョンで動作が変更
▌事象: Java SE 6u18でLogger#getLogger()メソッドが稀にnullを返す
◇ 参考 「JavaDoc (java.util.Logger#getLogger()メソッド)」
▌原因:
Logger#getLogger()メソッドでは、指定されたロガー名に対応するLoggerが存在しない場合、次の
順序でLoggerを取得して呼び出し元に返却
① Logger生成
② Loggerを弱参照マップに登録
③ 弱参照マップ登録したLoggerを取得
②と③の間にGCが発生すると、登録したLoggerがクリアされ、結果としてnullが返る
Page 21
© NEC Corporation 2015
6. java.util.Logger#getLogger()でnullを返却 (cont.)
▼Java SE 6u18のgetLogger()内部処理
private Hashtable<String,WeakReference<Logger>>
loggers = new Hashtable<String,WeakReference<Logger>>();
メモリリーク防止のためJava SE 6u18
から弱参照に変更
JVMによるコードの最適化
(イメージ)
Logger demandLogger(String name) {
Logger result = getLogger(name);
if (result == null) {
result = new Logger(name, null); private Hashtable<String,WeakReference<Logger>>
addLogger(result);
loggers = new Hashtable<String,WeakReference<Logger>>();
result = getLogger(name);
}
Logger demandLogger(String name) {
return result;
Logger result = getLogger(name);
}
if (result == null) {
addLogger(new Logger(name, null));
result = getLogger(name);
}
addLogger()終了後からgetLogger()
return result;
無駄な代入を省く最適化によりインスタ
までの間にGCが起こると、addLogger()
}
ンス化したLoggerがresult変数に参照さ
で Hashtableに弱参照で登録した
Loggerオブジェクトが消える
Page 22
© NEC Corporation 2015
れなくなるため、LoggerがGCによるクリ
アの対象になる
6. java.util.Logger#getLogger()でnullを返却 (cont.)
▌対処: Java SE 6u39以降を使う
Java SE 6u39以降ではLoggerオブジェクトが取得できるまで、ロガーの作成と取得を繰り返すように
Logger#getLogger()メソッドの内部実装が変更されている
▼Java SE 6u39の内部処理
Logger demandLogger(String name, String resourceBundleName) {
Logger result = getLogger(name);
if (result == null) {
Logger newLogger = new Logger(name, resourceBundleName);
do {
if (addLogger(newLogger)) {
return newLogger;
}
Loggerオブジェクトを取得
できるまで繰り返す
result = getLogger(name);
} while (result == null);
}
return result;
}
Page 23
© NEC Corporation 2015
7. 添付ファイル付きSOAPメッセージで例外
新しいUpdateバージョンで動作が変更
▌事象: Webサービス(JAX-WS)で添付ファイル付きSOAPメッセージを処理する際に例外発生
Metro 2.3.0バンドル版のJAX-WSが該当
Java SEに付属するJAX-WSでは発生しない
▌原因: Java SE 7u55でjavax.activation.CommandMap#getDefaultCommandMap()メソッド
に修正がされ、添付ファイル処理用に初期化を行ったCommandMapオブジェクトを取得でき
なくなっていた
初期化処理で添付ファイルを処理するためのハンドラを登録
動作時にハンドラが登録されていないCommandMapを取得し、添付ファイルの処理に失敗
Page 24
© NEC Corporation 2015
7. 添付ファイル付きSOAPメッセージで例外 (cont.)
▼Java SE 7u51以前
public static CommandMap getDefaultCommandMap(){
if (defaultCommandMap == null) {
defaultCommandMap = new MailcapCommandMap();
}
return defaultCommandMap;
}
▼Java SE 7u55以降
public static synchronized CommandMap getDefaultCommandMap(){
if (defaultCommandMap != null) {
return defaultCommandMap;
}
ClassLoader tccl = SecuritySupport.getContextClassLoader();
CommandMap def = (CommandMap)map.get(tccl);
if (def == null) {
def = new MailcapCommandMap();
map.put(tccl, def);
}
return def;
}
Page 25
© NEC Corporation 2015
クラスローダごとにCommandMap
を管理するよう変更。
Java SE 7u51までは
defaultCommandMapだけを保持
しており、初期化は初回取得時に
一度だけで良かった。
7. 添付ファイル付きSOAPメッセージで例外 (cont.)
▌対処
Bug_id:8043129
Metro 2.3.1バンドル版のJAX-WSを使用
• CommandMapの初期化タイミングを変更
(スタティックイニシャライザ → コンストラクタ)
• 初期化済みか否かのチェックを追加し、未初期化の場合のみ初期化処理を実行
▌その他
CommandMapを直接使用していなくても、JAX-WSのようにライブラリ側で対応できているか注意が
必要
MetroのWebサービスセキュリティ機能でも同様のロジックがあり、暗号化処理がスキップされる問題あ
り(Metro 2.3.1は未修整)
• レスポンスの暗号化結果が空になるだけでログに一切エラーが出ないため、原因の特定が難航
• 暗号化関連の処理を辿って延々とデバッグすることに (;_;)
Page 26
© NEC Corporation 2015
8. AWTでjava.lang.UnsatisfiedLinkErrorが発生
過去から長期にわたって不具合が修正されず
▌事象: Linux x86環境において、 JAWT(AWTのJNI用ライブラリ)にリンクされた自製ライブラ
リの呼び出しで、libmawt.soへのjava.lang.UnsatisfiedLinkErrorエラーが発生
java.lang.UnsatisfiedLinkError: Can't load library: /opt/curr/lib/headless/libmawt.so
$JAVA_HOME/jre/lib/amd64/headless/libmawt.soを参照することを期待していたが、
カレントディレクトリ(/opt/curr)からの相対パス(./lib/headless/libmawt.so)で検索が行われている
▌原因: AWT関連の仕様変更の影響により、動作プロセスのカレントディレクトリからの相対パス
でlibmawt.soが検索されるため
背景:
Java SE 5からAWTのライブラリがXToolkitとMToolkit(motifベース)に分離。どちらを利用するかは
実行時に決まり、AWTライブラリがロードされたときにのみ呼び出される。しかし、JAWT利用時はこの
ライブラリ選択処理がスキップされて参照パスが不正になり、上記の問題が発生
Page 27
© NEC Corporation 2015
8. AWTでjava.lang.UnsatisfiedLinkErrorが発生 (cont.)
▌発生条件: JAWTにリンクされた自製ライブラリをロードする
GUIを表示しないアプリケーションでも、例えば、javax.imageio.ImageIO#read()メソッドを呼び出した
延長でjava.awt.image.ColorModelクラスが利用され、本件と同じ事象が発生する。
▌対処: 不具合に抵触するUpdateバージョンを使用する場合は、動作プロセスのカレントディレ
クトリからAWTライブラリを検索できるようにシンボリックリンクを設定する
本件はJava SE 5~8で発生するが、現在公開されている最新版では改修済み
• 改修されたバージョン: 8u5、7u55、6u75、5u65
Page 28
© NEC Corporation 2015
Java SE 8 非互換項目の一覧 (1/2)
項番
Page 29
非互換項目
1
DatagramPacketコンストラクタの動作が変更
2
Java言語仕様の15.21項の内容を正しく適用
3
ジェネリクスが指定された型とRAW型における型チェックが変更
4
ある条件でProxyクラスがpublicからnon-publicに変更
5
Proxyクラスのコンストラクタの挙動が変更
6
CollectionインタフェースのremoveAllメソッドとretailAllメソッドの動作を変更
7
ソケットにポート番号を割り当てる範囲に関して挙動が変更
8
キーストロークがAWTKeyStrokeであるかのチェック方法を追加
9
JDK 8の制限付きパッケージにcom.sun.media.soundを追加
10
JDK 8の制限付きパッケージに com.sun.corba.se関連のパッケージを追加
11
DateFormatとSimpleDateFormatの出力形式が変更
12
BigDecimalクラスのstripTrailingZerosメソッドの戻り値が変更
13
コマンドラインのPermSizeとMaxPermSizeフラグが削除
14
NumberFormatクラスとDecimalFormatクラスの丸め動作を変更
© NEC Corporation 2015
非互換項目の種類
コンパイルができない
実行時に例外が発生
実行結果が異なる
Java SE 8 非互換項目の一覧 (2/2)
項番
非互換項目
15
合成ブリッジメソッドを生成するときの挙動が変更
16
Invokespecial命令の検証が変更
17
JVMでのACC_SUPERフラグの扱いが変更
18
TypeVariableクラスのgetUpperBoundメソッドの戻り値が変更
19
WWW-Authenticateレスポンス・ヘッダ内の値が一部変更
20
LocaleServiceProviderの実装が変更
21
JSSEプロバイダにおける新しいシステムプロパティが追加
22
Windowsにおけるuser.homeディレクトリの判別手順を変更
23
インタフェースの管理機能公開の条件を変更
24
“1.4.1”,”1.4.2”,”jsr14”がjavacで認識されないように変更
25
内部クラス用のコンストラクタを生成するときの挙動が変更
26
SecurityManager存在時におけるJAXPのXalan拡張関数が変更
27
JAXP関連のサービスプロバイダに関する挙動が変更
28
javax.xml.streamパッケージの一部クラスのnewFactoryメソッドの動作が変更
非互換項目の種類
実行結果が異なる
JDK 8の互換性ガイド http://www.oracle.com/technetwork/jp/java/javase/overview/8-compatibility-guide-2156366-ja.html
Page 30
© NEC Corporation 2015
Java SE 8適用の利点
▌様々なことがあったが、Java EEアプリケーションサーバにJava SE 7と8を適用した場合に
性能面で効果を確認
▌アプリケーション実行性能は9%向上、アプリケーションサーバ起動時間は27%短縮
1.20
Java SE 7u76
Java SE 8u40
1.00
0.80
0.60
【測定環境】
• CPU: Intel(R) Xeon(R) CPU E31270 @ 3.40GHz (4コア)
• RAM: 16GB
• OS : Red Hat Enterprise Linux 6.5
• AP Server: WebOTX Application Server Express V9.3
0.40
0.20
0.00
Page 31
Servletの
スループット
© NEC Corporation 2015
EJBの
スループット
アプリケーションサーバの
起動時間
Java SE 8 Metaspace領域の解析
気になるMetaspaceの使用状況
Java SE 8でパーマネント領域からMetaspace領域に代わり
OutOfMemoryErrorの発生頻度は減少
チューニング不要と思いきや、メモリリークしていたり、大量のメモリを使用する場合は
ネイティブ領域のメモリ空き容量が減少し、他のプロセスに影響を及ぼすことがある
メモリ関係でトラブルになった場合にMetaspaceの解析ができるように
なっておくことはJava開発者にとっては有益
Metaspaceの解析方法をご紹介!
Page 33
© NEC Corporation 2015
JEP 122:Remove the Permanent Generation
▌Java SE 8 からクラス情報は Native memory に移動!
Java Heap の世代は New と Old のみになり、Permanent は廃止!
<Java SE 7 以前>
Java Heap
From
Eden
Native Memory
To
Survivor
Young Generation
Tenure
Permanent
Old Generation
Permanent
Generation
Tenure
Metaspace
Thread Code
stack Cache
C Heap
Thread Code
stack Cache
C Heap
<Java SE 8 以降>
From
Eden
To
Survivor
Java Heap
Page 34
© NEC Corporation 2015
Native Memory
Metaspace領域の構造
▌Metaspace領域は、Metachunkリストの集合からなる仮想的な領域
ClassLoader単位に“a Metascpace”は作成される
“a Metaspace”は Metachunkのリストから構成される仮想的な領域
Metachunkは Native memory 内の Virtual space 内に確保される
Virtual space には複数のMetachunkが格納される
【Metaspace領域の各サイズ】
Reserved : Virtual space容量の合計
Metachunkリストは複数の Virtual space を跨ぐことがある
Bootstrap
ClassLoader
Young / Old
Java Heap
Native Memory
Metaspace
ClassLoader - A
“a Metaspace”
Virtual space 1
Metachunk
-Boot 1
Committed : Metachunk容量の合計
(Full GCによって空いた領域も含む)
Capacity : Metachunk使用量の合計
Metachunk
-A1
Metachunk
-A2
Metachunk
-A3
Block
© NEC Corporation 2015
Block
Page 35
Metachunk
-Boot 2
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Block
Committed Size
Reserved Size
Virtual space 2
Reserved
space
Metaspaceの拡張とチューニング・パラメータの関係
①
②
③
④
-XX:MaxMetaspaceSize=<NNN> (default:無制限)
-XX:MetaspaceSize=<NNN> (default:12MB ~ 22MB程度)
-XX:MinMetaspaceFreeRatio=<NNN>(default:40)
Full GC 発生後の High water mark
の拡張と縮小を制御
-XX:MaxMetaspaceFreeRatio=<NNN>(default:70)
MaxMetaspaceSize
①
High water mark
②
+ Metachunk Size
+ Metachunk Size
+ Metachunk Size
NEXT - High water mark
+ Allowed expand
Size
Request
Full GC
Request
Full GC
Compute
Next HWM
Committed
③
④
Used
0
Page 36
Compute
Next HWM
FullGC
© NEC Corporation 2015
FullGC
OutOfMemoryError: Compressed class space
※64bit OSの場合のみ
▌発生原因:
CompressedClassPointers 機能のための class space の枯渇が原因
Klass
Java Heap
Klass
Compressed Class Space
Bytecode
Bytecode
Metasapce
▌対処:以下の何れかを実施
① Compressed class space のサイズを増やす
 -XX:CompressedClassSpaceSize=<NNN>
(サイズは、1048576(1MB) ~ 3221225472(3GB) の間で指定する必要あり。デフォルトは1GB)
② Compressed class space を OFF にする
 -XX:-UseCompressedClassPointers
※補足:
Metaspace の枯渇を原因とする Full GC を発生させる閾値(HWM)の初期値(-XX:MetaspaceSize)も合わせてチューニングすることをお勧めします。
MetaspaceSize には Compressed Classs space のサイズも含まれます。
Page 37
© NEC Corporation 2015
OutOfMemoryError: Metaspace
▌発生原因:
メッセージの出力通り、Metaspace の枯渇が原因
Klass
Java Heap
Klass
Bytecode
Compressed Class Space
Bytecode
Metasapce
▌対処:
① Metaspace の最大サイズを指定している場合、その値を大きくする
 -XX:MaxMetaspaceSize=<NNN>
(またはオプションによるサイズ指定を止める!)
② Compressed Class Spaceが必要以上に大きい場合、その値を小さくする
 -XX:CompressedClassSpaceSize=<NNN>
(サイズは、1048576(1MB) ~ 3221225472(3GB) の間で指定する必要あり。デフォルトは1GB)
③ Java Heap が必要以上に大きい場合、その値を小さくする
 -Xmx<NNN> -Xms<NNN>
Page 38
© NEC Corporation 2015
-verbose:gc or -Xloggc のみ設定時のログの読み方
▌残念ながら通常のGCログでは Metaspace の状況は確認できません
Metaspce の状況はまったくログに出力されない
Metaspce が High Water Mark に達したことが原因で発生した Full GC を見分けるための情報
だけは出力される
[GC (Allocation Failure) 4059K->1399K(9920K), 0.0010878 secs]
[Full GC (Metadata GC Threshold) 2553K->1062K(9920K), 0.0125266 secs]
[GC (Allocation Failure) 3814K->1199K(9920K), 0.0007221 secs]
Metaspace
Virtual space 1
Metachunk
-Boot 1
?
Metachunk-B1
Metachunk-B2
Block
Block
Block
Block
Block
Block
Block
© NEC Corporation 2015
Block
Block
Block
Block
Page 39
Metachunk-A1
Virtual space 2
Reserved space
-XX:+PrintGCDetails 設定時のログの読み方
▌Full GC 発生時点での Metaspace の状況だけが確認できる
使用量に関しては Metaspace の箇所に限り、変化を表現していない
• Metaspace の Purge 処理は GC ログ出力後に実施される
Compressed Class Space を利用している場合
• 各数値には Compressed Class Space の使用量および容量が含まれている
[GC (Allocation Failure) [DefNew: 2883K->223K(3072K), 0.0009640 secs] 4059K->1399K(9920K), 0.0010878 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Metadata GC Threshold) [Tenured: 1175K->1062K(6848K), 0.0055470 secs] 2553K->1062K(9920K),
[Metaspace: 6552K->6552K(8576K)], 0.0125266 secs]
[Times: user=0.02 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [DefNew: 2752K->136K(3072K), 0.0006252 secs] 3814K->1199K(9920K), 0.0007221 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
Metachunk使用量の合計
Virtual space容量の合計
[Metaspace: ① -> ② (③)]
①②:Full GC 時点の Metaspace 全体の used 量
③ :Full GC 時点の Metaspace 全体の Reserved 量
Page 40
© NEC Corporation 2015
-XX:+PrintHeapAtGC 設定時のログの読み方 (1/2)
▌Full GC 後の状況ログから Metaspace の状況変化を確認できる!
{Heap before GC invocations=13 (full 2):
Before GC
def new generation total 3072K, used 1417K [0x04000000, 0x04350000, 0x04350000)
eden space 2752K, 43% used [0x04000000, 0x0412a660, 0x042b0000)
from space 320K, 69% used [0x04300000, 0x04337ef0, 0x04350000)
to space 320K, 0% used [0x042b0000, 0x042b0000, 0x04300000)
tenured generation total 6848K, used 1175K [0x04350000, 0x04a00000, 0x04a00000)
the space 6848K, 17% used [0x04350000, 0x04475e38, 0x04476000, 0x04a00000)
Metaspace
used 6552K, capacity 8510K, committed 8536K, reserved 8576K
[Full GC (Metadata GC Threshold) [Tenured: 1175K->1062K(6848K), 0.0055370 secs] 2592K->1062K(9920K),
[Metaspace: 6552K->6552K(8576K)], 0.0102723 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
Heap after GC invocations=14 (full 3):
After GC
def new generation total 3072K, used 0K [0x04000000, 0x04350000, 0x04350000)
eden space 2752K, 0% used [0x04000000,
0x04000000, 0x042b0000)
Metachunk
使用量の合計
from space 320K, 0% used [0x04300000, 0x04300000, 0x04350000)
to space 320K, 0% used [0x042b0000, 0x042b0000, 0x04300000)
tenured generation total 6848K, used 1062K [0x04350000, 0x04a00000, 0x04a00000)
the space 6848K, 15% used [0x04350000, 0x04459af0, 0x04459c00, 0x04a00000)
Metaspace
Metachunk 容量の合計
Virtual space 容量の合計
used 817K, capacity 2734K, committed 5464K, reserved 5504K
}
Virtual space 1
Metachunk
-Boot 1
Committed Size
Reserved Size
Page 41
© NEC Corporation 2015
Block
Vacant
space 3
Block
Vacant
space 2
Metachunk
-Boot 2
Block
Block
Block
Block
Block
Block
Vacant
space 1
Virtual space 2
Reserved
space
-XX:+PrintHeapAtGC 設定時のログの読み方 (2/2)
▌64bit OSの場合、Compressed Class Space の状況も出力される
Before GC
{Heap before GC invocations=3 (full 2):
def new generation total 19712K, used 1189K [0x00000000c0000000, 0x00000000c1560000, 0x00000000d5550000)
eden space 17536K, 3% used [0x00000000c0000000, 0x00000000c00abba0, 0x00000000c1120000)
from space 2176K, 23% used [0x00000000c1340000, 0x00000000c13bdc50, 0x00000000c1560000)
to space 2176K, 0% used [0x00000000c1120000, 0x00000000c1120000, 0x00000000c1340000)
tenured generation total 43712K, used 1103K [0x00000000d5550000, 0x00000000d8000000, 0x0000000100000000)
the space 43712K, 2% used [0x00000000d5550000, 0x00000000d5663d10, 0x00000000d5663e00, 0x00000000d8000000)
Metaspace
class space
used 12224K, capacity 12346K, committed 12448K, reserved 1060864K
used 1947K, capacity 2002K, committed 2048K, reserved 1048576K
After GC
[Full GC (Metadata GC Threshold) 1.569: [Tenured: 1103K->1353K(43712K), 0.0083164 secs] 2293K->1353K(63424K),
[Metaspace: 12224K->12224K(1060864K)], 0.0100021 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap after GC invocations=4 (full 3):
def new generation total 19712K, used 0K [0x00000000c0000000, 0x00000000c1560000, 0x00000000d5550000)
Metachunk容量の合計
eden space 17536K, 0% used [0x00000000c0000000,
0x00000000c0000000, 0x00000000c1120000)
Metachunk使用量の合計
from space 2176K, 0% used [0x00000000c1340000, 0x00000000c1340000, 0x00000000c1560000)
to space 2176K, 0% used [0x00000000c1120000, 0x00000000c1120000, 0x00000000c1340000)
tenured generation total 43712K, used 1353K [0x00000000d5550000, 0x00000000d8000000, 0x0000000100000000)
the space 43712K, 3% used [0x00000000d5550000, 0x00000000d56a2470, 0x00000000d56a2600, 0x00000000d8000000)
Metaspace
class space
起動時に確保した連続領域サイズ
used 7810K, capacity 7874K, committed 12448K, reserved 1060864K
used 1096K, capacity 1130K, committed 2048K, reserved 1048576K
}
Metaspace
class space
used ①, capacity ②, committed ③, reserved ④
used ⑤, capacity ⑥, committed ⑦, reserved ⑧
Compressed Class Space を除く通常の Metaspace のサイズを確認するには・・・
used ① ー ⑤, capacity ② ー ⑥, committed ③ ー ⑦, reserved ④ ー ⑧
Page 42
© NEC Corporation 2015
GC ログで Metasapce を確認する場合
▌最低でも以下のオプションを一緒に設定することをお勧めします!
 -Xloggc:<FILE>
 -XX:+PrintHeapAtGC
 -XX:+PrintGCDetails
▌クラスアンロードの詳細も確認したい場合、以下のオプションを上記オプションに追加する
必要があります
 -verbose:class
Page 43
© NEC Corporation 2015
jstat コマンドによる確認方法
▌実行例
▌実行例
 jstat -gc <Java PID>
▌出力結果
S0C
S1C
2176.0 2176.0
OU
MC
MU
CCSC CCSU YGC YGCT FGC FGCT GCT
4491.4 26104.0 21449.2 7928.0 3707.8 55
0.219 11 0.174 0.393
Metaspace の情報
 MC:現在の Metaspace Capacity(KB)
 MU:Metaspace Utilization(KB)
 CCSC:現在の Compressed Class Space Capacity(KB)
 CCSU:Compressed Class Space Used(KB)
Page 44
© NEC Corporation 2015
 jstat -gcmetacapacity <Java PID>
▌出力結果
MCMN
0.0
MCMX
1069056.0
MC
27336.0
CCSMN
0.0
CCSMX
1048576.0
CCSC
8136.0
YGC FGC FGCT
90
17
0.376
GCT
0.815
Metaspace の情報
 MCMN:Minimum Metaspace Capacity(KB)
 MCMX:Maximum Metaspace Capacity(KB)
 MC:Metaspace Capacity(KB)
 CCSMN: Minimum Compressed Class Space Capacity(KB)
 CCSMX: Maximum Compressed Class Space Capacity(KB)
 CCSC:Compressed Class Space Capacity(KB)
jmap コマンドによる確認方法
▌実行例
 jmap –J-d64 -clstats <Java PID>
※: 上記オプション内の “-J-d64” は、64bit Java VM の場合に限り設定する
▌出力結果
Attaching to process ID 296, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.25-b02
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader
classes bytes
parent_loader
alive?
type
<bootstrap>
662
1201022 null
live
<internal>
0x00000000d5577c40
0
0
null
dead sun/misc/Launcher$ExtClassLoader@0x0000000011a00448
0x00000000d5916068
474
483159 null
dead java/net/URLClassLoader@0x0000000011a000b0
0x00000000d55516b8
25
83246
0x00000000d5577c40 dead sun/misc/Launcher$AppClassLoader@0x0000000011a0a280
total = 4
1161
1767427
N/A
alive=1, dead=3
N/A
Metaspace に関連するクラスローダーの情報
Page 45
© NEC Corporation 2015
jcmd コマンドによる確認方法
▌実行例
▌実行例
 jcmd <Java PID> PerfCounter.print
 jcmd <Java PID> GC.class_stats
※ アタッチする Java AP は“-XX:+UnlockDiagnosticVMOptions”
を設定して起動する必要があります
▌出力結果
▌出力結果
・・・・ 省略
Compressed
Class Space
の情報
sun.gc.compressedclassspace.capacity=10690560
sun.gc.compressedclassspace.maxCapacity=1073741824
sun.gc.compressedclassspace.minCapacity=0
sun.gc.compressedclassspace.used=8932912
・・・・ 省略
Metaspace の
情報
sun.gc.metaspace.capacity=51060736
sun.gc.metaspace.maxCapacity=1115684864
sun.gc.metaspace.minCapacity=0
sun.gc.metaspace.used=48759312
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
1 -1 2954528
496
0 1152
14
121
2904 1120 3648 4768 java.lang.Object
2 -1 2260280
480
0
0
0
0
0
24 576 600 [I
3 -1 998560
480
0
0
0
0
0
24 576 600 [Ljava.lang.Object;
4 -1 433264
480
0
0
0
0
0
24 576 600 [C
5 1 169704
648
0 19304 130
4962 26392 16504 31600 48104 java.lang.Class
・・・・ 省略
1612
1613
1
0
544
0 1376
7
247
1280
880 2544 3424 sun.util.locale.LocaleObjectCache
1
0
496
0 1416
20
737
3736 2240 3672 5912 sun.util.locale.LocaleUtils
7333552 1329504 2736 3031360
17467 1131774 4163760 2822720 6212920 9035640 Total
81.2%
14.7%
0.0% 33.5%
- 12.5% 46.1% 31.2% 68.8% 100.0%
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
・・・・ 省略
Metaspace に格納されるクラス定義のヒストグラム
Page 46
© NEC Corporation 2015
Java VisualVM / JConsole による確認方法
▌実行例
▌実行例
 jvisualvm
 jconsole
▌出力結果
▌出力結果
「監視」タブで Metaspace の状況
(Compressed Class Space を含む)を確認する
「メモリ」タブで Metaspace / Compressed
Class Space の状況を確認する
Metaspace の情報
Metaspace の情報
Page 47
© NEC Corporation 2015
NECの取組み
高性能・高信頼なWeb/APサーバWebOTXがV9.3にバージョンアップ
2015年5月8日出荷予定
次世代のコンテナ型仮想化技術「Docker」を先取り!
▌主な機能強化内容
1. 高信頼基盤の性能と可用性を向上
高度な負荷分散構成
クラスタ運用が可能
 Web / APサーバ間の通信方式を刷新
Webサーバ #1
APサーバ #1
Express
Standard
Webサーバ #2
APサーバ #2
 通信速度を30%以上高速化
 Apache HTTP Server 2.4の最新化
 WebSocket、メモリ削減と高速化、負荷分散制御、クラ
スタ機能、最新SSL/TLSモジュールのバンドルなど
2. 最新のプラットフォームに対応
 Java SE 8、Red Hat Enterprise Linux 7
 Java SE 8を適用したAPサーバ起動性能は、Java SE 7
比で30%向上
 次世代の仮想化技術であるコンテナ型仮想技術
「Docker」に対応
クライアント
DB
サーバ
ロード
バランサ
Express
HTTP サーバ
Standard
アプリケーションサーバ
製品に関する詳細は以下のURLをご参照ください
http://jpn.nec.com/webotx/
クラウド環境への対応を強化! システムの仮想化、集約化での引合い多数!
Page 49
© NEC Corporation 2015
無料のお試し版としてAWS上でのシステム自動構築サンプルを公開中
WebOTX と一緒に Infrastructure as Code を体験!
http://jpn.nec.com/webotx/download/develop.html#aws
AWS
Management
Console
AWS
CloudFormation
AMI
template
EC2
instance
Amazon
RDS
システム設計に対する性能・可用性評価を支援するサービスも開始予定!
Page 50
© NEC Corporation 2015
進化し続ける「NEC WebOTX」。製品誕生から18年目へ
 初期バージョン発売以来、一貫して高性能・高信頼なサービス実行基盤を追求
 お客様ニーズや最新テクノロジーに対応し、ご利用のお客様がいる限りサポート
V10
V9
V8
Java EE 5
国際化対応
V7
V6
V5
V4
V3
V2
V1
OLTP
CORBA
Java対応等
EJB 1.1
RMI-IIOP
IIOP-SSL
J2EE 1.2
Webサービス
COBOL
J2EE 1.4
JDK 5.0
WS-BPEL 2.0
ESB (JBI 1.0)
高速XMLパーサ
統合IDE (Eclipse)
J2EE 1.3
CORBA 2.6
.NET
Java SE 6
IPv6
SIP
音声
RFID (EPCIS)
ISO/IEC 15408
Java EE 6
Java SE 7, 8
AWS
インメモリデータグリッド
クラウド、仮想化
バッチ
Java EE 7
準備中
Portal
NGN、ユビキタス
SOA
EJB 1.0
動的負荷分散
Webサービス
Java EE (Servlet/JSP、EJB、...)
• メインフレームの高信頼性技術に基づくトランザクション管理
• 分散オブジェクト (CORBA、COM)
’98
Page 51
’99
’00
’01
© NEC Corporation 2015
’02
’03
’04
’05
’06
’07
’08
’09
’10
’11
’12
’13
’14
’15~
おわりに
おわりに
▌商用ベンダとしての品質・サポートへのこだわり
▌タイムリな情報発信と製品提供でJavaの普及を促進
▌クラウドなど新たな領域でもJavaの活用を提案
これからもJavaの発展に貢献して参ります!!
Page 53
© NEC Corporation 2015