0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaのGC方式の決定条件について

Posted at

はじめに

JavaのGC方式(ParallelGC、G1GCなど)がオプションにより指定されていない場合、どのように決定されているかJavaVMソースコードで処理を追ってみた。
ソースは OpenJDK Java11 のもの。以下のソースパスで src/hotspot は省略している。

結論

先に結論を書くと、GC方式がオプションにより指定されていない場合、以下のようになる。

条件 GC方式
サーバクラスマシン UseG1GC
クライアントクラスマシン UseSerialGC

サーバクラスマシンは基本的にCPU2個以上かつメモリ約2G以上のマシン。

ソース詳細

JavaVM起動時に以下のような順で呼び出される。

Threads::create_vm (share/runtime/thread.cpp)
  Arguments::apply_ergo (share/runtime/arguments.cpp)
    Arguments::set_ergonomics_flags
      GCConfig::initialize (share/gc/shared/gcConfig.cpp)
        select_gc
          select_gc_ergonomically

各ソースを順に追っていく。

share/runtime/thread.cpp
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
  ....
  // Parse arguments
  // Note: this internally calls os::init_container_support()
  jint parse_result = Arguments::parse(args);
  if (parse_result != JNI_OK) return parse_result;

  os::init_before_ergo();

  jint ergo_result = Arguments::apply_ergo();   // ★
  if (ergo_result != JNI_OK) return ergo_result;
  ...

Arguments::parse でjavaの引数がパースされ、GC方式が指定されていると、そのオプションがtrueになる。
例えば -XX:+UseParallelGC なら、UseParallelGC がtrueになる。
基本的に、JVMの各オプションの値は、ソース上ではオプションの名前の変数が使われている。

share/runtime/arguments.cpp
jint Arguments::apply_ergo() {
  // Set flags based on ergonomics.
  jint result = set_ergonomics_flags();  //  ★
  if (result != JNI_OK) return result;

  .....

jint Arguments::set_ergonomics_flags() {
  GCConfig::initialize();   //  ★

  set_conservative_max_heap_alignment();
  .....
share/gc/shared/gcConfig.cpp
void GCConfig::initialize() {
  assert(_arguments == NULL, "Already initialized");
  _arguments = select_gc();  //  ★
}
....
GCArguments* GCConfig::select_gc() {
  // Fail immediately if an unsupported GC is selected
  fail_if_unsupported_gc_is_selected();

  if (is_no_gc_selected()) {   //  ★ GC方式が指定されていなかったら
    // Try select GC ergonomically
    select_gc_ergonomically();    //  ★ ここでGC方式を決定
    .....

is_no_gc_selected

is_no_gc_selected はどの方式も指定されてないとtrue、GC方式がすでに指定されていると、falseを返す。

share/gc/shared/gcConfig.cpp
bool GCConfig::is_no_gc_selected() {
  FOR_EACH_SUPPORTED_GC(gc) {   //  ★
    if (gc->_flag) {
      return false;
    }
  }

  return true;
}

FOR_EACH_SUPPORTED_GC は以下で定義。

# define FOR_EACH_SUPPORTED_GC(var)                                          \
  for (const SupportedGC* var = &SupportedGCs[0]; var < &SupportedGCs[ARRAY_SIZE(SupportedGCs)]; var++)

SupportedGCs にはサポートされているGC方式が羅列されている。

static const SupportedGC SupportedGCs[] = {
       CMSGC_ONLY_ARG(SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS,      cmsArguments,      "concurrent mark sweep gc"))
   EPSILONGC_ONLY_ARG(SupportedGC(UseEpsilonGC,       CollectedHeap::Epsilon,  epsilonArguments,  "epsilon gc"))
        G1GC_ONLY_ARG(SupportedGC(UseG1GC,            CollectedHeap::G1,       g1Arguments,       "g1 gc"))
  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelGC,      CollectedHeap::Parallel, parallelArguments, "parallel gc"))
  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelOldGC,   CollectedHeap::Parallel, parallelArguments, "parallel gc"))
    SERIALGC_ONLY_ARG(SupportedGC(UseSerialGC,        CollectedHeap::Serial,   serialArguments,   "serial gc"))
         ZGC_ONLY_ARG(SupportedGC(UseZGC,             CollectedHeap::Z,        zArguments,        "z gc"))
};

select_gc_ergonomically

ここでサーバクラスマシンか否かによってGC方式を決定する。

void GCConfig::select_gc_ergonomically() {
  if (os::is_server_class_machine()) {
# if INCLUDE_G1GC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);  // ★ サーバクラスマシンならG1GC
# elif INCLUDE_PARALLELGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
# elif INCLUDE_SERIALGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
# endif
  } else {
# if INCLUDE_SERIALGC
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);  // ★ クライアントクラスマシンならSerialGC
# endif
  }
}

is_server_class_machine

is_server_class_machine では、以下の条件でtrue(つまりサーバクラスマシン) または、false を返す。

条件 返却値
オプション NeverActAsServerClassMachine 指定時 false
オプション AlwaysActAsServerClassMachine 指定時 true
CPU2個以上かつメモリ約2G以上 true
それ以外 false
share/runtime/os.cpp
bool os::is_server_class_machine() {
  // First check for the early returns
  if (NeverActAsServerClassMachine) {  //★ NeverActAsServerClassMachine 指定の場合、サーバクラスマシンでないとみなす
    return false;
  }
  if (AlwaysActAsServerClassMachine) { //★ AlwaysActAsServerClassMachine 指定の場合、サーバクラスマシンとみなす。
    return true;
  }
  // Then actually look at the machine
  bool         result            = false;
  const unsigned int    server_processors = 2;
  const julong server_memory     = 2UL * G;
  // We seem not to get our full complement of memory.
  //     We allow some part (1/8?) of the memory to be "missing",
  //     based on the sizes of DIMMs, and maybe graphics cards.
  const julong missing_memory   = 256UL * M;

  /* Is this a server class machine? */  //★CPU2個以上かつメモリ約2G以上ならtrue
  if ((os::active_processor_count() >= (int)server_processors) &&
      (os::physical_memory() >= (server_memory - missing_memory))) {
    const unsigned int logical_processors =
      VM_Version::logical_processors_per_package();
    if (logical_processors > 1) {
      const unsigned int physical_packages =
        os::active_processor_count() / logical_processors;
      if (physical_packages >= server_processors) {
        result = true;
      }
    } else {
      result = true;
    }
  }
  return result;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?