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
© Copyright 2025 ExpyDoc