20130819 jjugnslt

1,581 views

Published on

Published in: Education, Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,581
On SlideShare
0
From Embeds
0
Number of Embeds
520
Actions
Shares
0
Downloads
6
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

20130819 jjugnslt

  1. 1. Aggressive Heap の実装を Aggressive に解析する JJUG Night Seminar Aug, 2013 Shinya TAKEBAYASHI
  2. 2. 自己紹介 v  名前: 竹林 信哉(たけばやし しんや) v  職業: 某 SIer 社員 ・・・ 少し前まで CGL 作っていました.今は Java サポート. v  得意: Ø  OS 実装 / デバイスドライバ / UNIX / Windows Ø  C / C++ / asm(x86, SPARC) / Python / 並列(CUDA) Ø  コンパイラ,デバッガとお友達 v  私と Java Ø  プログラミング言語 Java は苦手です Ø  JavaVM の実装が大好き @chi9rin
  3. 3. chi9 流 Hack の考え方 v  前提として Ø  アプリケーションは,そう簡単にソースコード通りに 動きません. Ø  環境に依存して,書いたソースをまねて動きます. Ø  プログラマやアーキテクトの腕の見せ所は,いかに狙った環境 で狙ったとおりに動かすか,です.
  4. 4. chi9 流 Hack の考え方(Cont’d) v  だから Ø  ソースコードばかりを追っていても,答えが得られない可能性 があります. Ø  ソースコードと実際の動作を見て,初めて実装を理解できます. ソースコードを読むのは予習 動いているものを trap して解析するのが Hack
  5. 5. -XX:+AggressiveHeap v  大規模アプリケーションにいいよ,という触れ込みの設定 v  自動でヒープサイズを決めてくれる v  結局何が指定されるかを解説したドキュメントが乏しい v  なのに皆さん勧めている謎の設定
  6. 6. -XX:+AggressiveHeap で 何が起きるか 計算 •  メモリサイズ •  GC スレッド数 機能の有効化 •  Parallel GC •  Large Pages •  JIT コンパイルポリシ はシンプルモード 機能の無効化 •  Scavenge GC •  TLAB の動的リサイズ julong initHeapSize; julong total_memory = os::physical_memory(); if (total_memory < (julong)256*M) { jio_fprintf(defaultStream::error_stream(), "You need at least 256mb of memory to use -XX:+AggressiveHeapn"); vm_exit(1); } initHeapSize = MIN2(total_memory / (julong)2, total_memory - (julong)160*M); initHeapSize = os::allocatable_physical_memory(initHeapSize); if (initHeapSize > MaxPermSize) { initHeapSize = initHeapSize - MaxPermSize; } else { warning("AggressiveHeap and MaxPermSize values may conflict"); } if (FLAG_IS_DEFAULT(MaxHeapSize)) { FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize); set_min_heap_size(initHeapSize); } if (FLAG_IS_DEFAULT(NewSize)) { FLAG_SET_CMDLINE(uintx, NewSize, ((julong)MaxHeapSize / (julong)8) * (julong)3); FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize); } FLAG_SET_DEFAULT(UseLargePages, true); FLAG_SET_CMDLINE(uintx, BaseFootPrintEstimate, MaxHeapSize); FLAG_SET_CMDLINE(bool, ResizeTLAB, false); FLAG_SET_CMDLINE(uintx, TLABSize, 256*K); FLAG_SET_CMDLINE(uintx, YoungPLABSize, 256*K); FLAG_SET_CMDLINE(uintx, OldPLABSize, 8*K); FLAG_SET_CMDLINE(intx, CompilationPolicyChoice, 0); FLAG_SET_CMDLINE(bool, UseParallelGC, true); FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100); FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true);
  7. 7. 答え パラメータ 最近のマシン環境で設定される値(青字は自動計算されるところ) -Xmx(MaxHeapSize) 物理メモリ量の半分 – 約 85 MB(LP64 の場合) -Xms(InitialHeapSize) MaxHeapSize と同じ -XX:NewSize (MaxHeapSize ÷ 8) × 3 -XX:MaxNewSize NewSize と同値 -XX:+UseLargePages 有効化 -XX:BaseFootPrintEstimates MaxHeapSize と同値 -XX:-ResizeTLAB 無効化 -XX:TALBSize 256KB -XX:YoungPLABSize 256KB -XX:OldPLABSize 8KB -XX:CompilationPolicyChoice 0(SimpleCompilePolicy) -XX:+UseParallelGC 有効化 -XX:ParallelGCThreads CPU 数が 8 以下なら CPU 数と同値,9 以上なら後述の計算式 -XX:ThreasholdTolerance 100 -XX:-ScavengeBeforeFullGC 無効化 -XX:+BindGCTaskThreadsToCPUs 有効化 ・ヒープ領域を多め(Aggressive!)に確保する. ・AP を全力(Aggressive!!)で走らせる. ・極力 GC しない.GC はまとめて全力(Aggressive!!!)で.
  8. 8. では,Hack を始めます 環境 CPU 4 cores – メモリ 2GB - Debian/GNU Linux 64 bits
  9. 9. JavaVM の準備 % hg clone http://hg.openjdk.java.net/jdk7u/jdk7u2 % cd jdk7u2 % chmod +x ./get_source.sh; ./get_source.sh % export ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk-amd64 % source jdk/make/jdk_generic_profile.sh % make sanity && make ALLOW_DOWNLOAD=true debug_build 【注意】 ・make -jn しないこと. ・gcc は 4.6 以前を使うこと.clang/clang++ は使わない. ・jdk7u25 以降は ZIP_DEBUGINFO_FILES=0 が必要
  10. 10. JavaVM 起動と進め方 v  コマンドラインオプションを解析する箇所にブレイクポイントを 仕掛ける. v  signal 6(SIGABRT)を投げて core を分析しても good! % ulimit –c unlimited % gdb ./java (gdb) b arguments.cpp:2458 No source file named arguments.cpp Make breakpoint pending on future shared library load? (y or [N]) y Breakpoint 1 (arguments.cpp:2458) pending. (gdb) r -XX:+AggressiveHeap ... Breakpoint 1, Arguments::parse_each_vm_init_arg ...... (gdb) signal 6 Continuing with signal SIGABRT. [Thread 0x7ffff7fd0700 (LWP 21391) exited] No unwaited-for children left.
  11. 11. 計算 その 1 そもそも AggressiveHeap が使えるかどうか v  物理メモリの算出と閾値判定 Ø  物理メモリ量の算出 p  = os::Linux::_physical_memory = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 物理ページ数 × ページサイズ = 513,535 × 4096 = 2,103,439,360 = /proc/meminfo の MemTotal 値 × 1,024(KB) Ø  判定: 256 MB 未満なら AggressiveHeap は使えない % gdb ./java (gdb) b arguments.cpp:2446 (gdb) r -XX:+AggressiveHeap Breakpoint 1, Arguments::parse_each_vm_init_arg (args=0x7ffff7fcfe20, scp_p=0x7ffff7fcea10, ... (gdb) p total_memory $1 = 2103439360 % grep MemTotal /proc/meminfo | awk '{print $2;}' | xargs -I n expr n * 1024 2103439360 julong total_memory = os::physical_memory(); if (total_memory < (julong)256*M) { jio_fprintf(defaultStream::error_stream(), "You need at least 256mb of memory to use -XX:+AggressiveHeapn"); vm_exit(1); }
  12. 12. 計算 その 2 ヒープサイズの計算 v  まず基準になるサイズを求め,次にヒープサイズを確定する. p  total_memory ÷ 2 または total_memory - 160 MB の小さい方 = 1,051,719,680 または 1,935,503,360 の小さい方 = 1,051,719,680 p  = 1,051,719,680 – 87,241,520 = 964,478,160 (← LP64) 1,051,719,680 – 67,108,864 = 984,610,816(← それ以外) % gdb ./java (gdb) b arguments.cpp:2469 (gdb) r -XX:+AggressiveHeap Breakpoint 1, Arguments::parse_each_vm_init_arg (args=0x7ffff7fcfe20, scp_p=0x7ffff7fcea10, ... (gdb) p MaxPermSize $2 = 87241520 (gdb) p initHeapSize $1 = 964478160 initHeapSize = MIN2(total_memory) / (julong) 2, total_memory – (julong)160 * M); if (initHeapSize > MaxPermSize) { initHeapSize = initHeapSize - MaxPermSize; } else { warning("AggressiveHeap and MaxPermSize values may conflict"); }
  13. 13. 計算 その 2(Cont’d) ヒープサイズの計算 v  確定した initHeapSize を MaxHeapSize,InitialHeapSize とし て設定. if (FLAG_IS_DEFAULT(MaxHeapSize)) { FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize); set_min_heap_size(initHeapSize); }
  14. 14. 計算 その 3 New 領域サイズの計算 v  算出した MaxHeapSize をもとに計算される. Ø  NewSize p  (MaxHeapSize / 8) * 3) = (964,478,160 ÷ 8) × 3 = 361,679,310 Ø  MaxNewSize p  上記で算出した NewSize と同値 % gdb ./java (gdb) b arguments.cpp:2482 (gdb) r -XX:+AggressiveHeap Breakpoint 1, Arguments::parse_each_vm_init_arg (args=0x7ffff7fcfe20, scp_p=0x7ffff7fcea10, ... (gdb) p MaxHeapSize $1 = 964478160 (gdb) p NewSize $2 = 361679310 (gdb) p MaxNewSize $3 = 361679310 FLAG_SET_CMDLINE(uintx, NewSize, ((julong)MaxHeapSize / (julong)8) * (julong)3); FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize);
  15. 15. 計算 その 4 GC スレッド数の算出 v  アクティブな CPU (/proc/cpuinfo の数)をもとに確定する. Ø  Abstract_VM_Version::nof_parallel_worker_threads() p  nof_parallel_worker_threads(num = 5, den = 8, switch_pt = 8) アクティブな CPU 数に応じて適切な値が計算される. p  アクティブ CPU 数が 8 以下なら,アクティブな CPU 数と同値. p  9 CPU 以上なら,8 + ((アクティブ CPU 数 – 8) × 5) ÷ 8) 例)アクティブ CPU 数が 72 なら 8 + ((72 – 8) × 5) ÷ 8) = 48 ス レッド. (gdb) b vm_version.cpp:307 (gdb) r -XX:+AggressiveHeap ... Breakpoint 1, Abstract_VM_Version::parallel_worker_threads () at ... (gdb) p _parallel_worker_threads $1 = 4 unsigned int ncpus = (unsigned int) os::active_processor_count(); return (ncpus <= switch_pt) ? ncpus : (switch_pt + ((ncpus - switch_pt) * num) / den);
  16. 16. おさらい パラメータ 最近のマシン環境で設定される値 GDB での出力 jinfo 出力 -Xmx(MaxHeapSize) 物理メモリ量の半分 – 約 85 MB -XX:MaxHeapSize=964478160 -Xms(InitialHeapSize) MaxHeapSize と同じ -XX:InitialHeapSize=964478160 -XX:NewSize (MaxHeapSize ÷ 8) × 3 -XX:NewSize=361679310 -XX:MaxNewSize NewSize と同値 -XX:MaxNewSize=361679310 -XX:+UseLargePages 有効化 -XX:+UseLargePages -XX:BaseFootPrintEstimates MaxHeapSize と同値 -XX:BaseFootPrintEstimates=964478160 -XX:-ResizeTLAB 無効化 -XX:-ResizeTLAB -XX:TLABSize 256KB -XX:TLABSize=262144 -XX:YoungPLABSize 256KB -XX:YoungPLABSize=262144 -XX:OldPLABSize 8KB -XX:OldPLABSize=8192 -XX:CompilationPolicyChoice 0(SimpleCompilePolicy) -XX:CompilationPolicyChoice=0 -XX:+UseParallelGC 有効化 -XX:+UseParallelGC -XX:ParallelGCThreads CPU 数が 8 以下なら CPU 数と同値 -XX:ParallelGCThreads=4 -XX:ThresholdTolerance 100 -XX:ThresholdTolerance=100 -XX:-ScavengeBeforeFullGC 無効化 -XX:-ScavengeBeforeFullGC -XX:+BindGCTaskThreadsToCPUs 有効化 -XX:+BindGCTaskThreadsToCPUs (gdb) p MaxHeapSize $1 = 964478160 (gdb) p InitialHeapSize $2 = 964478160 (gdb) p NewSize $3 = 361679310 (gdb) p MaxNewSize $4 = 361679310 (gdb) p UseLargePages $5 = true (gdb) p BaseFootPrintEstimate $6 = 964478160 (gdb) p ResizeTLAB $7 = false (gdb) p TLABSize $8 = 262144 (gdb) p YoungPLABSize $9 = 262144 (gdb) p OldPLABSize $10 = 8192 (gdb) p CompilationPolicyChoice $11 = 0 (gdb) p UseParallelGC $12 = true (gdb) p ParallelGCThreads $13 = 4 (gdb) p ThresholdTolerance $14 = 100 (gdb) p ScavengeBeforeFullGC $15 = false (gdb) p BindGCTaskThreadsToCPUs $16 = true
  17. 17. 最後に v  VM の実装を理解する勉強会をやりたい Ø  この手のネタを受け付ける人が身近には少ないので, ここで募集 v  JavaOne 2013@SFO 行きます v  次回予告 Ø  ByteCode / JIT コンパイラに優しいソースコード

×