• 検索結果がありません。

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

N/A
N/A
Protected

Academic year: 2022

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

Copied!
55
0
0

読み込み中.... (全文を見る)

全文

(1)

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

2015/04/08 日本電気株式会社

翁 信之介

(2)

目次

▌ はじめに

▌ Java SEバージョンアップの経験談

▌ Java SE 8 Metaspace領域の解析

▌ NECの取組み

▌ おわりに

本資料で使用するシステム名、製品名は、それぞれ各社の商標、または登録商標です。

なお、本文中ではTM、®、© マークを省略している箇所があります。

(3)

はじめに

(4)

Java EEの下層に位置するJava SEはOSと同様に品質が重要

▌ Java EEアプリケーションサーバにとってJava SEは肝であり、その品質がシステム全体に与え る影響は大きい

機能、性能、互換性、障害解析ツール、セキュリティ問題、etc.

OS

Java SE Java EE

Servlet / JSP EJB

Java VM

RMI-IIOP JNDI JAXP JDBC

JFS JAX-RS

JSON JTA JMS

JPA Batch

Solaris Linux Windows HP-UX

Driver CORBA Directory SV XML Parser

JMX Agent

StAX JAAS JAX-WS JAXB JAF SAAJ

(5)

▌ お客様からはOSSのアプリケーションサーバにはない、商用ベンダーならではの厳格な実装品 質と手厚いサポートの期待あり

旧互換性の維持

• 下層SWの振る舞い変更をAPサーバで回避

ex.) Java SEの仕様変更

• 異常系動作の結果やメッセージの維持

• 永年サポート (EJB 1.1 Container on JDK 1.2.2 ;-)

決して許されないデグレード

• 動作不正、性能劣化

• Java EE仕様が重厚になっても全パス試験に よる保証は、お客様にとって当たり前品質

セキュリティ脆弱性問題の迅速な対応

• 過去の製品に同梱した古いOSSに含まれた セキュリティ問題に対するパッチ提供

ex.) Struts 1、OpenSSL 0.9.x

商用ベンダーに求められる品質

特性 副特性

機能適合性 機能完全性、機能正確性、機能適切性 性能効率性 時間効率性、資源効率性、容量満足性 互換性 共存性、相互運用性

使用性 適切度認識性、習得性、運用操作性、ユーザエラー防 止性、ユーザインタフェース快美性、アクセシビリティ 信頼性 成熟性、可用性、障害許容性(耐故障性)、回復性

セキュリティ 機密性、インテグリティ、否認防止性、責任追跡性、真 正性

保守性 モジュール性、再利用性、解析性、修正性、試験性 移植性 適応性、設置性、置換性

ISO/IEC 25010 システム及びソフトウェア製品の品質要求及び評価(SQuaRE)

− システム及びソフトウェア品質モデル

(6)

商用ベンダーの悩み

ログ解析や運用状況のヒアリング等からの事象の分析 ソースコード調査

リリースメモ、JavaDocやマニュアルの確認 バグデータベースの検索

Webに公開されている一般情報 実機での再現検証 ・・・

お客様は即時回答を切望 動作不正

問合せ受付

製品不具合、業務アプリケーションのバグ 連携製品の問題、操作ミス ・・・

迅速、正確、丁寧な対応が顧客満足度に直結

お客様から見るとJava EEの下位層(Java SE、OS)も含めて「アプリケーションサーバ」

(7)

Java SE 8 サポートを急ぐ理由

▌ 前回のJava SE 6 EOLでは過去に例をみない大きな話題へと発展

お客様のセキュリティ問題に対する関心が急激に高くなったことが背景にあり

Java SEにセキュリティ問題がまだ潜在するにも

関わらずEOLが目前

行政からの注意喚起を基点に多くの業種で

Java SEのバージョンアップ要求が拡散。

メディアでも大きく取り上げられ、短期間に 問合せが殺到

Java SE 5以前で稼働中のシステムにも

最新化検討へ波及。ますます大きな騒ぎに 製品供給者としての社会的責任を果たすべく、

迅速な最新 Java SE 対応を推進

内閣官房情報セキュリティセンター (2014/7/17)

Java SE 6のサポート有効期間の満了に係る対応について(注意喚起) 一部抜粋 http://www.nisc.go.jp/active/general/pdf/javasupport_press_120717.pdf

直前に迫るJava SE 7 EOLについては

2015/3/3 内閣官房情報セキュリティセンター ウェブサイト等の利用者に使用を求めているソフトウェアのサポート終了に伴う対応 について(注意喚起)

http://www.nisc.go.jp/active/general/pdf/soft_150303.pdf

(8)

Java SE バージョンアップの経験談

(9)

▌ Java EEアプリケーションサーバ開発時の直面した、様々なアクシデントをご紹介

開発現場で遭遇した事象

Java SE 8で新規に発生

•Lambdaを使用したアプリケーションが配備できない

•wsimportコマンド実行時にエラーが発生

メジャーバージョンアップで動作が変更

•クラスローダーでデッドロック

新しいUpdateバージョンで動作が変更

•カスタムORBの初期化に失敗

•ロガーのインスタンスがすり替わる

•java.util.Logger#getLogger()でnullを返却

•添付ファイル付きSOAPメッセージで例外

過去から長期にわたって不具合が修正されず

•AWTでjava.lang.UnsatisfiedLinkErrorが発生

(10)

1. Lambdaを使用したアプリケーションが配備できない

▌ 事象: 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

タグバイト データ

Integer(0x03) の 42(0x0000000A)

12 00 00 00 26

タグバイト データ

?

Java SE 8で新規に発生

▼コンスタントプールの型

(11)

1. Lambdaを使用したアプリケーションが配備できない (cont.)

▌ 対処: ASMのバージョンアップ

クラスファイルの拡張自体はJava SE 7で行なわれたが、

Javaプログラムから生成されることはなかったため顕在化 しなかったと考えられる。

別のバイトコード操作ライブラリを利用したアプリケーション も注意が必要 (右表)

▼Apache Commons BCEL 5.2の実行結果

18(InvokeDynamic)が不正なバイトタグとして例外が発生している。

ライブラリ Java SE 8対応 バージョン

OW2 ASM 5.0

Javassist

(JBossのサブプロジェクト)

3.19.0-GA Apache Commons BCEL 6.0 RC

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)

言語仕様が拡張されると思いもよらぬところで非互換が発生する

▼OSSのバイトコード操作ライブラリ

(12)

2. wsimportコマンド実行時にエラーが発生

▌ 事象: 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では外部スキーマ参照時に セキュリティチェックが行われるように変更され、さらに、デフォルト設定では外部スキーマへのアクセ スが不可になっていた。

Java SE 8で新規に発生

(※)wsimportとは、WSDLファイルからWebサービスの動作に必要なクラスを生成するためのツール

(13)

2. wsimportコマンド実行時にエラーが発生 (cont.)

▌ 対処

一般的には下記のシステムプロパティを設定することで回避可能 (GlassFish 4.1では、domain.xmlにデフォルトで設定済)

XMLSchemaFactoryを使用してXML解析処理を実装している場合、setProperty()メソッドでアクセス 権限を付与することでも対処可能

javax.xml.accessExternalSchema=all

file、http、allなど、アクセス権を与えるプロトコルを指定

String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"

//JAXPXMLSchemaFactoryを取得

SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false);

//外部スキーマへのアクセス権限を付与

sf.setProperty(ACCESS_EXTERNAL_SCHEMA,"all");

Schema schema = sf.newSchema(source);

(14)

2. wsimportコマンド実行時にエラーが発生 (cont.)

▌ その他

XMLSchemaFactoryクラスを使用しており、かつ外部スキーマ参照があるXML解析を行っていると同 様の問題が発生する可能性あり

JAXPの仕様変更のようにデフォルトの挙動が変わることもあるので、バージョンアップ時の更新内容 をキャッチアップすることは重要

(15)

3. クラスローダでデッドロック

▌ 事象: アプリケーション実行中に不定期に デッドロックが発生

▌ 原因: 階層構造のクラスローダで逆方向の ロックが発生したため

Java SE 6までは、階層構造のクラスローダで 子から親の順番でロックするのが鉄則

Java stack information for the threads listed above:

===================================================

"Thread-0":

at java.lang.ClassLoader.loadClass(ClassLoader.java:404) - waiting to lock <0x099778f8> (a ParentClassLoader) at java.lang.ClassLoader.loadClass(ClassLoader.java:411) - locked <0x0998b920> (a ChildClassLoader)

at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at sample.Main$Loader.run(Main.java:61)

"main":

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)

at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

親クラスローダ 子クラスローダ

main

Thread-0

コンテキストクラス ローダに設定

ロック

ロック待ち

ロック ロック待ち

1 2

1

2

3

4

3

4

a. 親クラスローダでクラスロード中にパーミッション チェックを実行

(例えばaccessClassInPackageで権限が必要な“sun.”から始 まるパッケージのクラスのロード時)

b. sun.security.provider.PolicyFile#addPermissions()で コンテキストクラスローダを用いてクラスロード。し かし、コンテキストクラスローダは子クラスローダで あり、逆順のロックでデッドロックに至る

▼動作例

▼動作例におけるコールスタック

メジャーバージョンアップで動作が変更

(16)

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

それでもまだ問題は解消しない・・・

(17)

▌ 事象: Java SE 7u55にアップデートするとカスタムORBを利用したアプリケーションでの org.omg.ORB#init()メソッド呼び出しに失敗する

▌ 原因: システムプロパティ

「org.omg.CORBA.ORBSingletonClass」で 指定したORBSingletonクラスをロードする クラスローダの変更

7u51以前: スレッドにコンテキストクラスローダが 設定されていれば「コンテキストクラスローダ」。

そうでなければ「システムクラスローダ」

7u55: システムクラスローダのみ

8u5、6u75、5u65も同様に動作変更

クラスローダ階層(一部省略)

4. カスタムORBの初期化に失敗

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)

システムクラスローダ

APサーバのライブラリ用 クラスローダ

アプリケーションクラスローダ アプリケーションクラスローダ

アプリケーションクラスローダ ORBSingleton

新しいUpdateバージョンで動作が変更

ORB#init()実行時に コンテキストクラスロー ダへ設定したライブラ リ用クラスローダに ORBSingletonクラス をロードさせていた

(18)

4. カスタムORBの初期化に失敗 (cont.)

▌ リリースノートで示された対処:

カスタムORBのライブラリJarをシステムクラスローダでロードするようにライブラリ配置を変更

⇒ 納得いかずJava Bug Databaseに報告

バグとして認められ、製品としては修正された Updateバージョンの使用を告知

元に戻されたバージョン: 8u20、7u65、6u85、5u75

• Java SE 9ではこの動作が正式なものになる模様 →

システムクラスローダ

APサーバのライブラリ用 クラスローダ

アプリケーションクラスローダ アプリケーションクラスローダ

アプリケーションクラスローダ ORBSingleton

ただし Java SE 9は

Won't Fix

バグとして修正

JDK-8042789

(19)

5. ロガーのインスタンスがすり替わる

▌ 事象: Java SEを7u21以前から7u25に更新すると、あるタイミングでLogger#getLogger() 呼び出しで取得したLoggerが別インスタンスを返却するようになった。これにより、以前のイン スタンスで設定したログレベルなどの変更が無効になる。

▌ 原因: セキュリティマネージャー有効時、sun.awt.AppContextクラスのロード前後でロガー名を 管理する空間が別になったため

Appletの独立性を高める変更に影響

sun.awt.AppContextクラスはGUIを使用しなくとも、ImageIOなどを使用するとロードされる

Logger.getLogger("foo") -> java.util.logging.Logger@148662

Logger.getLogger("foo") -> java.util.logging.Logger@1829e6f

Logger before = Logger.getLogger("test");

Class.forName("sun.awt.AppContext");

Logger after = Logger.getLogger("test");

System.out.printf("before: %s, after: %s", before, after);

新しいUpdateバージョンで動作が変更

▼アプリケーションサーバ起動中

▼起動後

JDK-8024827

(20)

5. ロガーのインスタンスがすり替わる (cont.)

▌ 対処: 起動処理の早い段階で sun.awt.AppContext クラスロード処理を追加

他にも、システムプロパティ「javaplugin.version」あるいは「javawebstart.version」が設定されていれ ば発生しないことが判明。ただし、明示的に設定することに対する影響度は不明

または、Java SE 7u60で改修されたため、このUpdateバージョン以降を使用する

(21)

6. java.util.Logger#getLogger()でnullを返却

▌ 事象: Java SE 6u18でLogger#getLogger()メソッドが稀にnullを返す

▌ 原因:

Logger#getLogger()メソッドでは、指定されたロガー名に対応するLoggerが存在しない場合、次の 順序でLoggerを取得して呼び出し元に返却

① Logger生成

② Loggerを弱参照マップに登録

③ 弱参照マップ登録したLoggerを取得

②と③の間にGCが発生すると、登録したLoggerがクリアされ、結果としてnullが返る

◇ 参考 「JavaDoc (java.util.Logger#getLogger()メソッド)」

新しいUpdateバージョンで動作が変更

(22)

6. java.util.Logger#getLogger()でnullを返却 (cont.)

private Hashtable<String,WeakReference<Logger>>

loggers = new Hashtable<String,WeakReference<Logger>>();

Logger demandLogger(String name) { Logger result = getLogger(name);

if (result == null) {

result = new Logger(name, null);

addLogger(result);

result = getLogger(name);

}

return result;

}

private Hashtable<String,WeakReference<Logger>>

loggers = new Hashtable<String,WeakReference<Logger>>();

Logger demandLogger(String name) { Logger result = getLogger(name);

if (result == null) {

addLogger(new Logger(name, null));

result = getLogger(name);

}

return result;

}

JVMによるコードの最適化 (イメージ)

メモリリーク防止のためJava SE 6u18 から弱参照に変更

addLogger()終了後からgetLogger() までの間にGCが起こると、addLogger() で Hashtableに弱参照で登録した

Loggerオブジェクトが消える

無駄な代入を省く最適化によりインスタ ンス化したLoggerがresult変数に参照さ れなくなるため、LoggerがGCによるクリ アの対象になる

▼Java SE 6u18のgetLogger()内部処理

(23)

6. java.util.Logger#getLogger()でnullを返却 (cont.)

▌ 対処: Java SE 6u39以降を使う

Java SE 6u39以降ではLoggerオブジェクトが取得できるまで、ロガーの作成と取得を繰り返すように Logger#getLogger()メソッドの内部実装が変更されている

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;

}

result = getLogger(name);

} while (result == null);

}

return result;

}

Loggerオブジェクトを取得 できるまで繰り返す

▼Java SE 6u39の内部処理

(24)

7. 添付ファイル付きSOAPメッセージで例外

▌ 事象: Webサービス(JAX-WS)で添付ファイル付きSOAPメッセージを処理する際に例外発生

Metro 2.3.0バンドル版のJAX-WSが該当

Java SEに付属するJAX-WSでは発生しない

▌ 原因: Java SE 7u55でjavax.activation.CommandMap#getDefaultCommandMap()メソッド に修正がされ、添付ファイル処理用に初期化を行ったCommandMapオブジェクトを取得でき なくなっていた

初期化処理で添付ファイルを処理するためのハンドラを登録

動作時にハンドラが登録されていないCommandMapを取得し、添付ファイルの処理に失敗

新しいUpdateバージョンで動作が変更

(25)

7. 添付ファイル付きSOAPメッセージで例外 (cont.)

public static CommandMap getDefaultCommandMap(){

if (defaultCommandMap == null) {

defaultCommandMap = new MailcapCommandMap();

}

return defaultCommandMap;

}

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;

}

▼Java SE 7u51以前

▼Java SE 7u55以降

クラスローダごとにCommandMap を管理するよう変更。

Java SE 7u51までは

defaultCommandMapだけを保持 しており、初期化は初回取得時に 一度だけで良かった。

(26)

7. 添付ファイル付きSOAPメッセージで例外 (cont.)

▌ 対処

Metro 2.3.1バンドル版のJAX-WSを使用

• CommandMapの初期化タイミングを変更

(スタティックイニシャライザ → コンストラクタ)

• 初期化済みか否かのチェックを追加し、未初期化の場合のみ初期化処理を実行

▌ その他

CommandMapを直接使用していなくても、JAX-WSのようにライブラリ側で対応できているか注意が 必要

MetroのWebサービスセキュリティ機能でも同様のロジックがあり、暗号化処理がスキップされる問題あ り(Metro 2.3.1は未修整)

• レスポンスの暗号化結果が空になるだけでログに一切エラーが出ないため、原因の特定が難航

• 暗号化関連の処理を辿って延々とデバッグすることに (;_;)

Bug_id:8043129

(27)

8. AWTでjava.lang.UnsatisfiedLinkErrorが発生

▌ 事象: Linux x86環境において、 JAWT(AWTのJNI用ライブラリ)にリンクされた自製ライブラ リの呼び出しで、libmawt.soへのjava.lang.UnsatisfiedLinkErrorエラーが発生

▌ 原因: AWT関連の仕様変更の影響により、動作プロセスのカレントディレクトリからの相対パス でlibmawt.soが検索されるため

背景:

Java SE 5からAWTのライブラリがXToolkitとMToolkit(motifベース)に分離。どちらを利用するかは 実行時に決まり、AWTライブラリがロードされたときにのみ呼び出される。しかし、JAWT利用時はこの ライブラリ選択処理がスキップされて参照パスが不正になり、上記の問題が発生

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)で検索が行われている

(28)

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

(29)

Java SE 8 非互換項目の一覧 (1/2)

項番 非互換項目 非互換項目の種類

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クラスの丸め動作を変更

(30)

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

(31)

Java SE 8適用の利点

▌ 様々なことがあったが、Java EEアプリケーションサーバにJava SE 7と8を適用した場合に 性能面で効果を確認

▌ アプリケーション実行性能は9%向上、アプリケーションサーバ起動時間は27%短縮

0.00 0.20 0.40 0.60 0.80 1.00 1.20

Java SE 7u76 Java SE 8u40

Servletの スループット

EJBの スループット

アプリケーションサーバの 起動時間

【測定環境】

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

(32)

Java SE 8 Metaspace領域の解析

(33)

気になるMetaspaceの使用状況

Java SE 8でパーマネント領域からMetaspace領域に代わり OutOfMemoryErrorの発生頻度は減少

チューニング不要と思いきや、メモリリークしていたり、大量のメモリを使用する場合は ネイティブ領域のメモリ空き容量が減少し、他のプロセスに影響を及ぼすことがある

メモリ関係でトラブルになった場合にMetaspaceの解析ができるように なっておくことはJava開発者にとっては有益

Metaspaceの解析方法をご紹介!

(34)

JEP 122:Remove the Permanent Generation

Java SE 8 からクラス情報は Native memory に移動!

Java Heap の世代は New と Old のみになり、Permanent は廃止!

Eden

From To

Tenure Survivor

Young Generation Old Generation

Thread

stack C Heap

Permanent Generation Permanent

Eden

From To

Tenure

Survivor Thread

stack C Heap

Metaspace

< Java SE 7 以前>

< Java SE 8 以降>

Java Heap

Java Heap

Native Memory

Native Memory

Code Cache

Code Cache

(35)

Metaspace領域の構造

▌ Metaspace領域は、Metachunkリストの集合からなる仮想的な領域

ClassLoader単位に“a Metascpace”は作成される

“a Metaspace”は Metachunkのリストから構成される仮想的な領域

Metachunkは Native memory 内の Virtual space 内に確保される

Virtual space には複数のMetachunkが格納される

Metachunkリストは複数の Virtual space を跨ぐことがある

Java Heap

Metachunk -Boot 1

Virtual space 1 Virtual space 2

Metachunk -A1

Metachunk -A2

ClassLoader - A Bootstrap

ClassLoader Young / Old

Metaspace

Metachunk -Boot 2 Metachunk

-A3

Block Block Block Block Block Block Block Block Block Block Block Block Block

Block Block

Native Memory “a Metaspace”

Reserved space

Reserved Size

Committed Size

【Metaspace領域の各サイズ】

Reserved: Virtual space容量の合計 Committed: Metachunk容量の合計

(Full GCによって空いた領域も含む) Capacity: Metachunk使用量の合計

(36)

Metaspaceの拡張とチューニング・パラメータの関係

① -XX:MaxMetaspaceSize=<NNN> (default:無制限)

-XX:MetaspaceSize=<NNN>

(default:12MB ~ 22MB程度)

③ -XX:MinMetaspaceFreeRatio=<NNN>(default:40)

④ -XX:MaxMetaspaceFreeRatio=<NNN>(default:70)

High water mark

FullGC Used

MaxMetaspaceSize

Committed

0

+ Metachunk Size

FullGC + Allowed expand

Size

NEXT - High water mark

Request Full GC

Request Full GC

Compute Next HWM

Compute Next HWM

Full GC 発生後の High water mark の拡張と縮小を制御

+ Metachunk Size + Metachunk Size

(37)

OutOfMemoryError: Compressed class space

▌ 発生原因:

CompressedClassPointers 機能のための class space の枯渇が原因

▌ 対処:以下の何れかを実施

① Compressed class space のサイズを増やす

 -XX:CompressedClassSpaceSize=<NNN>

(サイズは、1048576(1MB) ~ 3221225472(3GB) の間で指定する必要あり。デフォルトは1GB)

② Compressed class space を OFF にする

 -XX:-UseCompressedClassPointers

Compressed Class Space Metasapce

Klass Klass Bytecode

Bytecode

※補足:

Metaspace の枯渇を原因とする Full GC を発生させる閾値(HWM)の初期値(-XX:MetaspaceSize)も合わせてチューニングすることをお勧めします。

MetaspaceSize には Compressed Classs space のサイズも含まれます。

Java Heap

※64bit OSの場合のみ

(38)

OutOfMemoryError: Metaspace

▌ 発生原因:

メッセージの出力通り、Metaspace の枯渇が原因

▌ 対処:

① Metaspace の最大サイズを指定している場合、その値を大きくする

 -XX:MaxMetaspaceSize=<NNN>

(またはオプションによるサイズ指定を止める!)

② Compressed Class Spaceが必要以上に大きい場合、その値を小さくする

 -XX:CompressedClassSpaceSize=<NNN>

(サイズは、1048576(1MB) ~ 3221225472(3GB) の間で指定する必要あり。デフォルトは1GB)

③ Java Heap が必要以上に大きい場合、その値を小さくする

 -Xmx<NNN> -Xms<NNN>

Compressed Class Space Metasapce

Klass Klass Bytecode

Bytecode

Java Heap

(39)

-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]

Metachunk -Boot 1

Virtual space 1 Virtual space 2

Metachunk-A1 Metachunk-B1 Metachunk-B2

Block Block Block Block Block Block Block Block Block

Block Block

Metaspace

Reserved space

(40)

-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 量

(41)

-XX:+PrintHeapAtGC 設定時のログの読み方 (1/2)

▌ Full GC 後の状況ログから

Metaspace の状況変化を確認できる!

{Heap before GC invocations=13 (full 2):

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):

def new generation total 3072K, used 0K [0x04000000, 0x04350000, 0x04350000) eden space 2752K, 0% used [0x04000000, 0x04000000, 0x042b0000)

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 used 817K, capacity 2734K, committed 5464K, reserved 5504K

}

Metachunk容量の合計

Metachunk使用量の合計 Virtual space 容量の合計

Before GCAfter GC

Metachunk -Boot 1

Virtual space 1 Virtual space 2

Metachunk -Boot 2

Block Block Block Block Block Block Block Block

Vacant space 1

Vacant space 3

Reserved space

Reserved Size

Committed Size

Vacant space 2

(42)

-XX:+PrintHeapAtGC 設定時のログの読み方 (2/2)

64bit OSの場合、Compressed Class Space の状況も出力される

{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 used 12224K, capacity 12346K, committed 12448K, reserved 1060864K class space used 1947K, capacity 2002K, committed 2048K, reserved 1048576K

[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) eden space 17536K, 0% used [0x00000000c0000000, 0x00000000c0000000, 0x00000000c1120000)

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 used 7810K, capacity 7874K, committed 12448K, reserved 1060864K class space used 1096K, capacity 1130K, committed 2048K, reserved 1048576K

}

Metachunk容量の合計 Metachunk使用量の合計

起動時に確保した連続領域サイズ

Before GCAfter GC

Metaspace used ①, capacity ②, committed ③, reserved ④ class space used ⑤, capacity ⑥, committed ⑦, reserved ⑧

Compressed Class Space を除く通常の Metaspace のサイズを確認するには・・・

used ① ー ⑤, capacity ② ー ⑥, committed ③ ー ⑦, reserved ④ ー ⑧

(43)

GC ログで Metasapce を確認する場合

▌ 最低でも以下のオプションを一緒に設定することをお勧めします!

 -Xloggc:<FILE>

 -XX:+PrintHeapAtGC

 -XX:+PrintGCDetails

▌ クラスアンロードの詳細も確認したい場合、以下のオプションを上記オプションに追加する 必要があります

 -verbose:class

(44)

jstat コマンドによる確認方法

▌ 実行例

jstat -gc <Java PID>

▌ 出力結果

MC:現在の Metaspace Capacity(KB)

MU:Metaspace Utilization(KB)

CCSC:現在の Compressed Class Space Capacity(KB)

CCSU:Compressed Class Space Used(KB)

S0C S1C OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 2176.0 2176.0 4491.4 26104.0 21449.2 7928.0 3707.8 55 0.219 11 0.174 0.393

Metaspace の情報

▌ 実行例

jstat -gcmetacapacity <Java PID>

▌ 出力結果

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)

MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT 0.0 1069056.0 27336.0 0.0 1048576.0 8136.0 90 17 0.376 0.815

Metaspace の情報

(45)

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 に関連するクラスローダーの情報

(46)

jcmd コマンドによる確認方法

▌ 実行例

jcmd <Java PID> PerfCounter.print

▌ 出力結果

・・・・ 省略

sun.gc.compressedclassspace.capacity=10690560

sun.gc.compressedclassspace.maxCapacity=1073741824 sun.gc.compressedclassspace.minCapacity=0

sun.gc.compressedclassspace.used=8932912

・・・・ 省略

sun.gc.metaspace.capacity=51060736

sun.gc.metaspace.maxCapacity=1115684864 sun.gc.metaspace.minCapacity=0

sun.gc.metaspace.used=48759312

・・・・ 省略

Compressed Class Space の情報

Metaspace の 情報

▌ 実行例

jcmd <Java PID> GC.class_stats

▌ 出力結果

アタッチする Java AP は“-XX:+UnlockDiagnosticVMOptions”

を設定して起動する必要があります

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 1 0 544 0 1376 7 247 1280 880 2544 3424 sun.util.locale.LocaleObjectCache 1613 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 に格納されるクラス定義のヒストグラム

(47)

Java VisualVM / JConsole による確認方法

▌ 実行例

jvisualvm

▌ 出力結果

「監視」タブで Metaspace の状況

(Compressed Class Space を含む)を確認する

Metaspace の情報

▌ 実行例

jconsole

▌ 出力結果

「メモリ」タブで Metaspace / Compressed Class Space の状況を確認する

Metaspace の情報

(48)

NECの取組み

(49)

高性能・高信頼なWeb/APサーバWebOTXがV9.3にバージョンアップ

次世代のコンテナ型仮想化技術「Docker」を先取り!

http://jpn.nec.com/webotx/

2015年5月8日出荷予定

DB クライアント サーバ

Express

ロード バランサ

主な機能強化内容

1. 高信頼基盤の性能と可用性を向上

 Web / APサーバ間の通信方式を刷新

通信速度を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」に対応

製品に関する詳細は以下のURLをご参照ください

Webサーバ #1

Webサーバ #2

APサーバ #1

APサーバ #2 Standard

Express Standard

HTTP サーバ アプリケーションサーバ 高度な負荷分散構成

クラスタ運用が可能

クラウド環境への対応を強化! システムの仮想化、集約化での引合い多数!

(50)

無料のお試し版としてAWS上でのシステム自動構築サンプルを公開中

AWS

Management Console

AWS

CloudFormation template

AMI EC2

instance

Amazon RDS

WebOTX と一緒に Infrastructure as Code を体験!

http://jpn.nec.com/webotx/download/develop.html#aws

システム設計に対する性能・可用性評価を支援するサービスも開始予定!

(51)

進化し続ける「NEC WebOTX」。製品誕生から18年目へ

J2EE 1.2 Webサービス

COBOL EJB 1.1

RMI-IIOP IIOP-SSL EJB 1.0

動的負荷分散 OLTP

CORBA Java対応等

V6 V5

V4 V3

V2 V1

Webサービス

Java EE (Servlet/JSP、EJB、...)

メインフレームの高信頼性技術に基づくトランザクション管理

分散オブジェクト (CORBA、COM)

SOA

NGN、ユビキタス

Java SE 6 IPv6

SIP 音声 RFID (EPCIS) ISO/IEC 15408

’98

V10

J2EE 1.4 JDK 5.0 WS-BPEL 2.0 ESB (JBI 1.0) 高速XMLパーサ 統合IDE (Eclipse) J2EE 1.3

CORBA 2.6

.NET Portal

バッチ

クラウド、仮想化

V7

’99 ’00 ’01 ’02 ’03 ’04 ’05 ’06 ’07 ’08 ’09 ’10 ’11 ’12 ’13 ’14

V8

Java EE 5 国際化対応

Java EE 6 Java SE 7, 8

AWS

インメモリデータグリッド

’15

Java EE 7 準備中

V9

初期バージョン発売以来、一貫して高性能・高信頼なサービス実行基盤を追求

お客様ニーズや最新テクノロジーに対応し、ご利用のお客様がいる限りサポート

(52)

おわりに

(53)

おわりに

▌ 商用ベンダとしての品質・サポートへのこだわり

▌ タイムリな情報発信と製品提供でJavaの普及を促進

▌ クラウドなど新たな領域でもJavaの活用を提案

これからもJavaの発展に貢献して参ります!!

(54)
(55)

参照

関連したドキュメント

for the observed functions, smooth.type a string with the name of smoothing method to be used (B-splines or Fourier), nbasis a numeric value defining the number of basis functions

[3] Chen Guowang and L¨ u Shengguan, Initial boundary value problem for three dimensional Ginzburg-Landau model equation in population problems, (Chi- nese) Acta Mathematicae

Its Tamari polynomial B T (x) counts the trees smaller than or equal to T in the Tamari order according to the number of nodes on their

品名(Part name) 数量(Quantity).. 品名(Part name) 数量(Quantity).. 品名(Part name) 数量(Quantity).. 部品番号 (Part No.) 品名(Part name)

In this diagram, there are the following objects: myFrame of the Frame class, myVal of the Validator class, factory of the VerifierFactory class, out of the PrintStream class,

We now prove that the second cohomology groups of irreducible peculiar modules which are not mentioned in the formulation of theorem 1.1 are trivial.. The lists of highest weights

・ここに掲載する内容は、令和 4年10月 1日現在の予定であるため、実際に発注する建設コンサル

[r]