Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

GCを発生させないJVMとコーディングスタイル

1,131 views

Published on

HotSpotに実装されているEscape Analysisの解説

Published in: Software
  • Be the first to comment

  • Be the first to like this

GCを発生させないJVMとコーディングスタイル

  1. 1. 2018年12月15日 数村 憲治 GCを発生させない JVMとコーディングスタイル Copyright 2018 FUJITSU LIMITED0 JJUG CCC 2018 Fall
  2. 2. .setName(“数村憲治”) .setDirectorOf(“Eclipse Foundation Board”) .setMemberOf(“Jakarta EE Committee”) .setMemberOf(“JCP Executive Committee”) .setTwitter(“@kkzr”) .setResponsibleFor(“Launcher”) .build(); スピーカー Copyright 2018 FUJITSU LIMITED Speaker me = SpeakerBuilder 1
  3. 3. アジェンダ Copyright 2018 FUJITSU LIMITED GC問題 アプリケーションによる対処 コンパイラによる対処 サマリ 2
  4. 4. アジェンダ Copyright 2018 FUJITSU LIMITED GC問題 アプリケーションによる対処 コンパイラによる対処 サマリ 3
  5. 5. 何が問題か Copyright 2018 FUJITSU LIMITED 健康診断シンドローム アプリケーションの実行が止まる アプリケーションに割り当てられるCPU時間が減る 実はたいした問題ではない 4 スループット レスポンス
  6. 6. なぜ問題か Copyright 2018 FUJITSU LIMITED (Cでは、malloc/free回数に依存) チューニングがたいへん 最適解をみつけるのが難しい 環境が変わるとやりなおし 見積もりができない GC時間は残存オブジェクトに依存 5
  7. 7. 問題の対処方法 Copyright 2018 FUJITSU LIMITED あきらめる SLAの妥協 Javaを使わない オブジェクトの 生成数・量を減らす アプリケーションで頑張る GCで頑張る コンパイラで頑張る 優秀なGCを作る オブジェクトの 生成を最適化 6
  8. 8. デモ Copyright 2018 FUJITSU LIMITED7 Node.js $ node –trace-gc node.js $ graalvm-ce-1.0.0-rc10/bin/node --jvm.Xmx16m --jvm.Xms16m --jvm.verbose:gc node.js
  9. 9. アジェンダ Copyright 2018 FUJITSU LIMITED GC問題 アプリケーションによる対処 コンパイラによる対処 サマリ 8
  10. 10. アプリケーションで頑張る Copyright 2018 FUJITSU LIMITED オブジェクトプール (キャッシュ) スレッドプール コネクションプール 小ネタ ArrayList 拡張 String.intern() Boxing/Unboxing 9
  11. 11. Integer AutoBoxing Copyright 2018 FUJITSU LIMITED10 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } キャッシュの範囲はプロパティで指定可能 java.lang.Integer.IntegerCache.high よく使われる範囲はIntegerオブジェクトの使いまわし Integer.java
  12. 12. プーリングコスト Copyright 2018 FUJITSU LIMITED 1*(メモリ割当+初期化) + p*GCp n*(メモリ割当+初期化) + u*GCu プーリング使用時 プーリング不使用時 n: トランザクション回数 p: プーリング使用時のGC回数 u: プーリング不使用時のGC回数 GCp: プーリング使用時の1回のGC時間 GCu: プーリング不使用時の1回のGC時間 p < u GCp > GCu 初期化 < n*初期化 メモリ割当は問題にならない 11 一般的な傾向
  13. 13. Edenからのアロケーション Copyright 2018 FUJITSU LIMITED o = new Object(); bottom top end lock(Eden); top = top + size; unlock(Eden); Bump The Pointer bottom top end 12 size
  14. 14. TLAB (Thread-Local Allocation Buffer) Copyright 2018 FUJITSU LIMITED スレッド1スレッド2 Eden領域をスレッドごとに分割して割当て ロックが不要に 13 lock(Eden); top = top + size; unlock(Eden);
  15. 15. Fast Allocation Copyright 2018 FUJITSU LIMITED https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf only requiring around 10 native instructions Memory Management in the Java HotSpot Virtual Machine Bump the Pointer + TLAB で実現 14
  16. 16. デモ Copyright 2018 FUJITSU LIMITED15 Bump The Pointer $ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp -XX:CompileCommand=compileonly,Bump.doIt -XX:-UseTLAB Bump $ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp -XX:CompileCommand=compileonly,Bump.doIt Bump (注)PrintAssemblyを使うには、hsdisが必要。https://github.com/liuzhengyang/hsdis
  17. 17. TLABが向かないケース Copyright 2018 FUJITSU LIMITED スレッド N+1 用のTLABが割当てられない スレッド1スレッド2 スレッドN ・・・ スレッド数が多く、かつ、オブジェクト生成量が少ない場合 16
  18. 18. デモ Copyright 2018 FUJITSU LIMITED17 Thread-Local Allocation Buffer $ java -Xmx32m -Xms32m -verbose:gc TLAB $ java -Xmx32m -Xms32m -verbose:gc -XX:-UseTLAB TLAB
  19. 19. アジェンダ Copyright 2018 FUJITSU LIMITED GC問題 アプリケーションによる対処 コンパイラによる対処 サマリ 18
  20. 20. デモ Copyright 2018 FUJITSU LIMITED19 メモリアロケーション量とGC頻度 $ java -Xmx32m -Xms32m -verbose:gc EA
  21. 21. Escape Analysis (EA) Copyright 2018 FUJITSU LIMITED https://docs.oracle.com/javase/8/docs/technotes/guides/vm/performance- enhancements-7.html JDK 6 (HotSpot C2) から採用 JITによる最適化 Scalar Replacement Stack Allocation Lock Elision 20
  22. 22. Escapeとは Copyright 2018 FUJITSU LIMITED メソッドからの脱出 オブジェクトがアロケートされたメソッドの外で 使用されているかもしれない オブジェクトはメソッドローカルでない スレッドからの脱出 オブジェクトがアロケートされたスレッドの外で 使用されているかもしれない 他のスレッドがそのオブジェクトにアクセスするかもしれない 21
  23. 23. Escapeの種類 Copyright 2018 FUJITSU LIMITED オブジェクトはグローバルに脱出する オブジェクトは作成したメソッドを脱出しない オブジェクトは引数経由でメソッドを脱出するが、 スレッドは脱出しない NoEscape ArgEscape GlobalEscape 22
  24. 24. Escapeの例 Copyright 2018 FUJITSU LIMITED int foo(String name) { Person person = new Person(name); return person.id(); } void foo(String name) { Person person = new Person(name); register(person); } NoEscape ArgEscape 23
  25. 25. Escapeの例 Copyright 2018 FUJITSU LIMITED class bar { Person person; void foo(String name) { person = new Person(name); } } GlobalEscape 24
  26. 26. 最適化の組み合わせ Copyright 2018 FUJITSU LIMITED Scalar Replacement Stack Allocation Lock Elision No Escape 〇 〇 〇 Arg Escape - - 〇 Global Escape - - - 25
  27. 27. Stack Allocation Copyright 2018 FUJITSU LIMITED オブジェクトをヒープではなくスタックにアロケートする メソッド終了と同時にオブジェクトは解放 HotSpotでは不採用 26
  28. 28. Stack Allocation Copyright 2018 FUJITSU LIMITED ヘッダ 32 山田 太郎 SP メソッド 開始時 new Person() 実行後 メソッド 終了時 残骸 SP SP 27 void foo { Person person = new Person(32, “山田太郎”); ・・・ スタック
  29. 29. Scalar Replacement Copyright 2018 FUJITSU LIMITED オブジェクトフィールドへのアクセスを、 スタックまたはレジスターアクセスにする Stack Allocationとは異なり、 オブジェクトヘッダー等はアロケートされない 28
  30. 30. Scalar Replacement 例 Copyright 2018 FUJITSU LIMITED int foo(String name, int age) { Person person = new Person(name, age); return person.getAge(); } class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } } 29
  31. 31. デモ Copyright 2018 FUJITSU LIMITED30 Scalar Replacement $ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=print,ScalarReplace.doIt -XX:-DoEscapeAnalysis ScalarReplace $ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=print,ScalarReplace.doIt -XX:+DoEscapeAnalysis ScalarReplace $ java -verbose:gc -Xmx32m -Xms32m -XX:CompileCommand=dontinline,ScalarReplace.getPersonId ScalarReplace
  32. 32. Lock Elision Copyright 2018 FUJITSU LIMITED スレッドローカルなオブジェクトに対するロックを削除 31 void foo() { Object lock = new Ojbect(); synchronized (lock) { //doSomething }; }
  33. 33. アジェンダ Copyright 2018 FUJITSU LIMITED GC問題 アプリケーションによる対処 コンパイラによる対処 サマリ 32
  34. 34. サマリ Copyright 2018 FUJITSU LIMITED GCの問題と対処 JVMの種類やインライン状況によっては、 GCが発生したり、しなかったり 33 まずは、見やすいコードを GCは日々改善されている Javaのアロケーションコストは低い EAによるメモリ最適化もあり
  35. 35. Copyright 2018 FUJITSU LIMITED Q/A 34

×