Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JVM in Action

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

JVM in Action

Avatar for Go Tanaka

Go Tanaka

July 20, 2017
Tweet

More Decks by Go Tanaka

Other Decks in Programming

Transcript

  1. 001 _mark _klass Fields 32-bit cpu 64-bit cpu 4 byte

    8 byte 4 byte 8 byte -XX:ObjectAlignmentInBytes=8 ͢΂ͯͷΦϒδΣΫτ͸όΠτڥքʹ഑ஔ͞ΕΔ PCKFDUIFBEFS NBSLXPSE LMBTTQPJOUFS
  2. java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 16

    (object header) N/A Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total +0-Ͱग़ྗͯ͠Έͨ݁Ռ new Object() すると、64-bit cpu では 16 byte 消費することになる 001
  3. 001ͱ,MBTTͷؔ܎ InstanceOop _klass InstanceKlass InstanceKlass _super *OTUBODF0PQTUS ,MBTT4USJOH ,MBTT0CKFDU Metaspace

    InstanceOop PPQ$MBTT4USJOH _java_mirror Java Heap String str = “hoge”; InstanceMirrorKlass _klass
  4. .BSL hash age CJU CJU unused:25 hash:31 -->| unused:1 age:4

    biased_lock:1 lock:2 (normal object) hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) src/share/vm/oops/markOop.hpp ʢྫʣ6OMPDLFE ޙड़ ͷ.BSLͷϝϞϦߏ଄ hash age
  5. .BSLͷঢ়ଶ#JBTFE  ΦϒδΣΫτׂ͕Γ౰ͯΒΕΔ  #JBTFE-PDLJOH͸+BWB͔ΒσϑΥϧτͳͷͰCJBTBCMFPCKFDUʹͳΔ  ϩοΫ͢ΔͱUISFBE*%͕ઃఆ͞ΕΔ CJBTFEPCKFDU  

    SFCJBT͢ΔͱCJBTBCMFPCKFDUʹ໭Δ ҰఆपظͰSFCJBT͢ΔΒ͍͠   ଞͷεϨουͰར༻͞ΕΔͱجຊϩοΫʹͳΔ #JBTFE-PDLJOH͕ղআ͞ΕΔ 0 epoch age 1 01 thread ID epoch age 1 01 JOJUJBMMPDL SFCJBT CJBTBCMFPCKFDU CJBTFEPCKFDU
  6. .BSLͷঢ়ଶ hash code age 0 01 pointer to lock record

    00  #JBTFE-PDLJOH͕ར༻Ͱ͖ͳ͍৔߹͸جຊϩοΫͷϓϩηεʹͳΔ  جຊϩοΫͰϩοΫ͢Δͱ5IJO-PDL͕͔͔Δ  εϨου͕͢ͰʹͦͷΦϒδΣΫτͷϩοΫΛ͍࣋ͬͯΔ৔߹͸3FDVSTJWF-PDLʹͳΔ  ฒߦॲཧͳͲͰෳ਺ͷҟͳΔεϨου͔Βಉ͡ΦϒδΣΫτʹରͯ͠ ಉ࣌ʹಉظॲཧ͕ߦΘΕΔͱ*OqBUF-PDLʹͳΔ pointer to heavyweight monitor 10 6OMPDLFE -JHIUXFJHIU-PDLFE )FBWZXFJHIU-PDLFE 5IJO-PDL *OqBUF-PDL ʜVOMPDLFE ʜMPDLFE ʜNPOJUPS
  7. ϝϞϦϨΠΞ΢τ _mark _klass Fields 32-bit cpu 64-bit cpu 4 byte

    8 byte 4 byte 8 byte -XX:ObjectAlignmentInBytes=8 ͢΂ͯͷΦϒδΣΫτ͸όΠτڥքʹ഑ஔ͞ΕΔ PCKFDUIFBEFS NBSLXPSE LMBTTQPJOUFS
  8. java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 16

    (object header) N/A Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total ѹॖ001ͳ͠ java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ѹॖ001͋Γ ϝϞϦϨΠΞ΢τ
  9. class A { byte a; int c; short d; long

    e; Object f; } ᶃ ᶄ ᶆ ᶅ ᶇ jol.samples.A object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 16 (object header) N/A 16 8 long D.e N/A 24 4 int D.c N/A 28 2 short D.d N/A 30 1 byte D.a N/A 31 1 (alignment/padding gap) 32 8 java.lang.Object D.f N/A Instance size: 40 bytes Space losses: 1 bytes internal + 0 bytes external = 1 bytes total ᶃ ᶄ ᶅ ᶆ ᶇ ѹॖ001ͳ͠ ϝϞϦϨΠΞ΢τ
  10. class A { byte a; int c; short d; long

    e; Object f; } ᶃ ᶄ ᶆ ᶅ ᶇ jol.samples.A object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int D.c N/A 16 8 long D.e N/A 24 2 short D.d N/A 26 1 byte D.a N/A 27 1 (alignment/padding gap) 28 4 java.lang.Object D.f N/A Instance size: 32 bytes Space losses: 1 bytes internal + 0 bytes external = 1 bytes total ᶃ ᶄ ᶅ ᶆ ᶇ ѹॖ001͋Γ ϝϞϦϨΠΞ΢τ
  11. class A { byte a; } class B extends A

    { long b; short c; byte d; } jol.samples.B object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 1 byte A.a N/A 13 3 (alignment/padding gap) 16 8 long B.b N/A 24 2 short B.c N/A 26 1 byte B.d N/A 27 5 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 3 bytes internal + 5 bytes external = 8 bytes total ϝϞϦϨΠΞ΢τ
  12. +0-Ͱ$MBTT-BZPVUΛΈͯΈΔ java.lang.String object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0

    4 (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) da 02 00 f8 12 4 char[] String.value [H, e, l, l, o, , W, o, r, l, d] 16 4 int String.hash 0 20 4 (loss due to the next object alignment) Instance size: 24 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ϝϞϦϨΠΞ΢τ
  13. +0-ͰΠϯελϯεͷ(SBQI-BZPVUΛΈͯΈΔ java.lang.String@532760d8d object externals: ADDRESS SIZE TYPE PATH VALUE 76b98fb58

    24 java.lang.String (object) 76b98fb70 40 [C .value [H, e, l, l, o, , W, o, r, l, d] DIBSͷ഑ྻͰCZUFফඅ͍ͯ͠Δ ϝϞϦϨΠΞ΢τ
  14. [C object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4

    (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) 41 00 00 f8 12 4 (object header) 0b 00 00 00 16 22 char [C.<elements> N/A 38 2 (loss due to the next object alignment) Instance size: 40 bytes Space losses: 0 bytes internal + 2 bytes external = 2 bytes total ͜ͷDIBSͷ഑ྻͷ$MBTT-BZPVUΛΈͯΈΔ <) F M M P  8 P S M E>͸ཁૉ਺YC ഑ྻͷ௕͕͞ϔομʹઃఆ͞ΕΔ ϝϞϦϨΠΞ΢τ
  15. String str = “Hello World”; ͜ͷ+BWBΦϒδΣΫτ͸ԿCZUFͷϝϞϦΛফඅ͢Δ͔ 4USJOHCZUF DIBS<>CZUF ߹ܭɿCZUF ϝϞϦϨΠΞ΢τ

    _mark _klass char[] String.value int String.hash padding _mark _klass length char [C.<elements> padding CZUF CZUF         4USJOH DIBS<>
  16. +7.ͷιʔείʔυ IPUTQPU IPUTQPUຊମ MJCKWN Λ࡞ΔͨΊͷ.BLFpMFͱιʔείʔυΛೲΊͨσΟϨΫτϦ KEL MJCKWNҎ֎ͷϥΠϒϥϦΛ࡞ΔͨΊͷϑΝΠϧ .BLFpMF ιʔείʔυ ٴͼ+BWB

    ͷඪ४ϥΠϒϥϦ༻ͷιʔείʔυ KBWBϑΝΠϧ ΛೲΊͨσΟϨΫτϦ MBOHUPPMT MBOHVBHFUPPMT KBWBD KBWBEPD KBWBI KBWBQ BQU౳ Λ࡞ΔͨΊͷ.BLFpMFͱιʔ είʔυΛೲΊͨσΟϨΫτϦ http://hsmemo.github.io/articles/noazh2rR49.html ˞ଞʹ΋ͨ͘͞Μ͋Δ
  17. +7.ͷιʔείʔυ PPQT +BWBͷΦϒδΣΫτ؅ཧ +BWBΦϒδΣΫτͷ಺෦දݱ ʹؔ͢Διʔείʔυ SVOUJNF )PU4QPUͷϥϯλΠϜػೳʹؔ͢Διʔείʔυ NFNPSZ +BWBώʔϓ؅ཧʹؔ͢Διʔείʔυ DMBTTpMF

    ΫϥεϑΝΠϧ؅ཧ ΫϥεϩʔσΟϯάॲཧ΋ؚΉ ʹؔ͢Διʔείʔυ JOUFSQSFUFS ΠϯλʔϓϦλؔ࿈ͷιʔείʔυ QSJNT +/*΍+7.5* TVONJTDVOTBGF౳ʹؔ͢Διʔείʔυ http://hsmemo.github.io/articles/nopoim3uPN.html IPUTQPUTSDTIBSFWNҎԼ ˞ଞʹ΋ͨ͘͞Μ͋Δ
  18. +7.ͷىಈ   ίϚϯυϥΠϯҾ਺Λղੳ͢ΔɻͦͷଞͷҾ਺͸7.ʹ౉͞ΕΔ   ώʔϓαΠζ͓ΑͼελοΫαΠζΛઃఆ͢Δ   +7.λΠϓ͓Αͼ؀ڥม਺Λઃఆ͢Δ

      .BJOΫϥεΛಡΈࠐΉ   ৽͘͠࡞੒͞ΕͨεϨου಺Ͱ7.Λ࡞੒͢Δ   7.͕ॳظԽ͞Εɺ.BJO$MBTT͔ΒϝΠϯϝιουͷଐੑΛऔಘ͢Δ   ϝΠϯϝιουΛݺͼग़͢   ϝΠϯϝιου࣮ߦ׬ྃޙɺൃੜͨ͠ྫ֎ΛνΣοΫɺFYJUεςʔλεΛฦ٫   ϝΠϯεϨουΛσλονɻσλον͢ΔͱεϨουΧ΢ϯτΛσΫϦϝϯτ͢Δ ɹɹ͜ΕʹΑΓ%FTUSPZ+BWB7.Λ҆શʹݺͼग़͢͜ͱ͕Ͱ͖Δ +/*@$SFBUF+BWB7. IPUTQPUTSDTIBSFWNQSJNFTKOJDQQ ͋ͨΓ͕ಛʹॏཁ
  19. +7.ͷىಈ   ίϚϯυϥΠϯҾ਺Λղੳ͢ΔɻͦͷଞͷҾ਺͸7.ʹ౉͞ΕΔ   ώʔϓαΠζ͓ΑͼελοΫαΠζΛઃఆ͢Δ   +7.λΠϓ͓Αͼ؀ڥม਺Λઃఆ͢Δ

      .BJOΫϥεΛಡΈࠐΉ   ৽͘͠࡞੒͞ΕͨεϨου಺Ͱ7.Λ࡞੒͢Δ   7.͕ॳظԽ͞Εɺ.BJO$MBTT͔ΒϝΠϯϝιουͷଐੑΛऔಘ͢Δ   ϝΠϯϝιουΛݺͼग़͢   ϝΠϯϝιου࣮ߦ׬ྃޙɺൃੜͨ͠ྫ֎ΛνΣοΫɺFYJUεςʔλεΛฦ٫   ϝΠϯεϨουΛσλονɻσλον͢ΔͱεϨουΧ΢ϯτΛσΫϦϝϯτ͢Δ ɹɹ͜ΕʹΑΓ%FTUSPZ+BWB7.Λ҆શʹݺͼग़͢͜ͱ͕Ͱ͖Δ +/*@$SFBUF+BWB7. IPUTQPUTSDTIBSFWNQSJNFTKOJDQQ ͋ͨΓ͕ಛʹॏཁ ͜ͷ΁Μ·Ͱʢ؆ུԽͨ͠ʣιʔείʔυΛ௥ͬͯΈ͍ͨͱࢥ͍·͢
  20. +7.ͷىಈ ΤϯτϦϙΠϯτʢKELVEFWʣ http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/3462d04401ba/src/share/bin/main.c int main(int argc, char **argv) { int

    margc; char** margv; const jboolean const_javaw = JNI_FALSE; margc = argc; margv = argv; return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, FULL_VERSION, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, (const_launcher != NULL) ? const_launcher : *margv, (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, const_cpwildcard, const_javaw, const_ergo_class); }
  21. +7.ͷىಈ ίϚϯυϥΠϯҾ਺Λղੳ͢ΔɻͦͷଞͷҾ਺͸7.ʹ౉͞ΕΔ http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/share/bin/java.c int JLI_Launch(…) { InitLauncher(javaw); // 初期化 SelectVersion(argc,

    argv, &main_class); // JREバージョンの選択 CreateExecutionEnvironment(…); // JVMタイプおよび環境変数を設定 // JVMをロード。ifn->CreateJavaVM = JNI_CreateJavaVM が設定される if (!LoadJavaVM(jvmpath, &ifn)) { return(6); } // コマンドライン引数を解析 if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) { return(ret); } SetJavaCommandLineProp(what, argc, argv); SetJavaLauncherProp(); SetJavaLauncherPlatformProps(); return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); }
  22. +7.ͷىಈ ώʔϓαΠζ͓ΑͼελοΫαΠζΛઃఆ͢Δ http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/share/bin/java.c void AddOption(char *str, void *info) { //

    ParseArguments() から実行 if (JLI_StrCCmp(str, "-Xss") == 0) { jlong tmp; if (parse_size(str + 4, &tmp)) { threadStackSize = tmp; } } if (JLI_StrCCmp(str, "-Xmx") == 0) { jlong tmp; if (parse_size(str + 4, &tmp)) { maxHeapSize = tmp; } } if (JLI_StrCCmp(str, "-Xms") == 0) { jlong tmp; if (parse_size(str + 4, &tmp)) { initialHeapSize = tmp; } } }
  23. +7.ͷىಈ +7.λΠϓ͓Αͼ؀ڥม਺ʢ-%@-*#3"3:@1"5)ʣΛઃఆ͢Δ http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/solaris/bin/java_md_solinux.c void CreateExecutionEnvironment(...) { SetExecname(*pargv); // 実行ファイル名を設定 if

    (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { // 使用するJREを取得 exit(2); } if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { // 指定されたJVMタイプを検索(jvm.cfg) exit(1); } // JVMタイプをチェック (-client, -server を削除) jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { exit(4); } if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) { exit(4); } // LD_LIBRARY_PATH を取得 runpath = getenv(LD_LIBRARY_PATH); execve(...); }
  24. +7.ͷىಈ .BJOΫϥεΛಡΈࠐΉ int JNICALL JavaMain(void * _args) { JavaMainArgs *args

    = (JavaMainArgs *)_args; InvocationFunctions ifn = args->ifn; // JVMの初期化 if (!InitializeJVM(&vm, &env, &ifn)) { // ifn->CreateJavaVM(JNI_CreateJavaVM)を実行 exit(1); } mainClass = LoadMainClass(env, mode, what); // メインクラスをロード // JavaFXなどでメインクラスがコマンドラインで指定されていない場合 // JARのマニフェストファイルにある Main-Class の名前を読み込む appClass = GetApplicationClass(env); mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); // アプリケーションのコマンドライン引数を設定 mainArgs = CreateApplicationArgs(env, argv, argc); // メインメソッドを実行 (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); // 例外を捕捉 ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; } http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/share/bin/java.c
  25. +7.ͷىಈ ৽͘͠࡞੒͞ΕͨεϨου಺Ͱ7.Λ࡞੒͢Δ int JVMInit(...) { ShowSplashScreen(); return ContinueInNewThread(ifn, threadStackSize, argc,

    argv, mode, what, ret); } http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/solaris/bin/java_md_solinux.c int ContinueInNewThread(...) { JavaMainArgs args; args.argc = argc; args.argv = argv; args.ifn = *ifn; // 新しいスレッドを作成してメインメソッドを実行 rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); return (ret != 0) ? ret : rslt; } http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e74259b3eadc/src/share/bin/java.c
  26. int JLI_Launch(int argc, char ** argv, /* main argc, argc

    */ int jargc, const char** jargv, /* java args */ int appclassc, const char** appclassv, /* app classpath */ const char* fullversion, /* full version defined */ const char* dotversion, /* dot version defined */ const char* pname, /* program name */ const char* lname, /* launcher name */ jboolean javaargs, /* JAVA_ARGS */ jboolean cpwildcard, /* classpath wildcard*/ jboolean javaw, /* windows-only javaw */ jint ergo /* ergonomics class policy */ ) { InitLauncher(javaw); // JLI_SetTraceLauncherしてる DumpState(); if (JLI_IsTraceLauncher()) { int i; printf("Command line args:\n"); for (i = 0; i < argc ; i++) { printf("argv[%d] = %s\n", i, argv[i]); } AddOption("-Dsun.java.launcher.diag=true", NULL); } +7.ͷىಈॲཧ·ΘΓͷখωλ
  27. static void DumpState() { if (!JLI_IsTraceLauncher()) return ; printf("Launcher state:\n");

    printf("\tdebug:%s\n", (JLI_IsTraceLauncher() == JNI_TRUE) ? "on" : "off"); printf("\tjavargs:%s\n", (_is_java_args == JNI_TRUE) ? "on" : "off"); printf("\tprogram name:%s\n", GetProgramName()); printf("\tlauncher name:%s\n", GetLauncherName()); printf("\tjavaw:%s\n", (IsJavaw() == JNI_TRUE) ? "on" : "off"); printf("\tfullversion:%s\n", GetFullVersion()); printf("\tdotversion:%s\n", GetDotVersion()); printf("\tergo_policy:"); switch(GetErgoPolicy()) { case NEVER_SERVER_CLASS: printf("NEVER_ACT_AS_A_SERVER_CLASS_MACHINE\n"); break; case ALWAYS_SERVER_CLASS: printf("ALWAYS_ACT_AS_A_SERVER_CLASS_MACHINE\n"); break; default: printf("DEFAULT_ERGONOMICS_POLICY\n"); } } +7.ͷىಈॲཧ·ΘΓͷখωλ
  28. +7.ͷىಈॲཧ·ΘΓͷখωλ void JLI_SetTraceLauncher() { if (getenv(JLDEBUG_ENV_ENTRY) != 0) { _launcher_debug

    = JNI_TRUE; JLI_TraceLauncher("----%s----\n", JLDEBUG_ENV_ENTRY); } } openjdk/jdk8u/jdk/src/share/bin/jli_util.h 33:#define JLDEBUG_ENV_ENTRY "_JAVA_LAUNCHER_DEBUG"
  29. $ export _JAVA_LAUNCHER_DEBUG=1 $ java Hello ----_JAVA_LAUNCHER_DEBUG---- Launcher state: debug:on

    javargs:off program name:java launcher name:java javaw:off fullversion:1.8.0_131-b11 dotversion:1.8 ergo_policy:DEFAULT_ERGONOMICS_POLICY Command line args: argv[0] = /usr/bin/java argv[1] = Hello JRE path is /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre jvm.cfg[0] = ->-server<- jvm.cfg[1] = ->-client<- 6957 micro seconds to parse jvm.cfg Default VM: server ~ +7.ͷىಈॲཧ·ΘΓͷখωλ