摘要

Java开发者常常依赖JVM的自动内存管理,当堆内存不足时,垃圾回收器(Garbage Collector,GC)会被触发以回收空间。然而,GC操作并非由触发分配的Java线程直接执行,而是通过一个专门的JVM内部线程——VMThread——来调度和执行。本文将基于OpenJDK 17的源码,深入剖析一个Java线程在分配对象时遇到内存不足,如何请求并等待GC完成,以及VMThread如何响应、执行垃圾回收的完整链路。我们将从G1CollectedHeap::attempt_allocation出发,经过attempt_allocation_slowdo_collection_pause,到VMThread::executeVMThread::loop,揭示JVM背后精巧的协作机制。通过源码级别的逐行解读,读者将对JVM的内存分配与GC触发有更深刻的理解。


1. 引言

JVM(Java Virtual Machine)的自动内存管理是其核心优势之一。Java线程在堆上分配对象时,如果空闲内存不足以满足分配请求,JVM会触发一次垃圾回收(Garbage Collection,GC)来释放不再使用的对象。但GC操作通常是重量级的,需要暂停应用线程(Stop-The-World,STW)或部分暂停,且必须安全地执行。为了保证线程安全和状态一致性,JVM将这些需要全局协调的操作委托给一个专门的线程——VMThread(有时也称为“VM线程”或“GC线程”)。

VMThread负责执行各种VM内部操作(VM_Operation),包括但不限于垃圾回收、偏向锁撤销、线程转储等。Java线程在需要执行这些操作时,不会直接运行,而是将请求封装为一个VM_Operation对象,交给VMThread排队执行,并等待结果。

本文将围绕G1垃圾回收器(G1 GC)展开,分析Java线程在分配小对象时内存不足,如何一步步触发GC,以及VMThread如何执行VM_G1CollectForAllocation操作来完成GC并返回分配结果。我们将引用OpenJDK 17的源码片段,确保解析的准确性和深度。


2. Java线程的对象分配路径

在G1 GC下,Java线程分配对象通常采用TLAB(Thread Local Allocation Buffer)或直接在Eden区分配。但当TLAB空间不足或分配请求较大时,会进入慢速分配路径。

2.1 分配入口:G1CollectedHeap::attempt_allocation

g1CollectedHeap.cpp中,G1CollectedHeap::attempt_allocation是分配的入口函数:

cpp

inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size,
                                                     size_t desired_word_size,
                                                     size_t* actual_word_size) {
  assert_heap_not_locked_and_not_at_safepoint();
  assert(!is_humongous(desired_word_size), "attempt_allocation() should not "
         "be called for humongous allocation requests");

  HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size);

  if (result == NULL) {
    *actual_word_size = desired_word_size;
    result = attempt_allocation_slow(desired_word_size);
  }

  assert_heap_not_locked();
  if (result != NULL) {
    assert(*actual_word_size != 0, "Actual size must have been set here");
    dirty_young_block(result, *actual_word_size);
  } else {
    *actual_word_size = 0;
  }

  return result;
}
  • 首先尝试通过_allocator->attempt_allocation快速分配(可能从当前线程的TLAB或Eden区空闲块中分配)。

  • 如果返回NULL,表示快速分配失败,则调用attempt_allocation_slow进入慢速分配路径。

assert_heap_not_locked_and_not_at_safepoint()确保当前不在GC暂停中且没有持锁,否则分配可能引发死锁或破坏状态。

2.2 慢速分配:attempt_allocation_slow

attempt_allocation_slow函数位于g1CollectedHeap.cpp中,代码较长,我们逐步解析其核心逻辑:

cpp

HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
  ResourceMark rm; // For retrieving the thread names in log messages.

  assert_heap_not_locked_and_not_at_safepoint();
  assert(!is_humongous(word_size), "attempt_allocation_slow() should not "
         "be called for humongous allocation requests");

  HeapWord* result = NULL;
  for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
    bool should_try_gc;
    bool preventive_collection_required = false;
    uint gc_count_before;

    {
      MutexLocker x(Heap_lock);

      // 重新尝试分配(在持有Heap_lock的情况下)
      size_t actual_size;
      result = _allocator->attempt_allocation(word_size, word_size, &actual_size);
      if (result != NULL) {
        return result;
      }

      preventive_collection_required = policy()->preventive_collection_required(1);
      if (!preventive_collection_required) {
        result = _allocator->attempt_allocation_using_new_region(word_size);
        if (result != NULL) {
          return result;
        }

        // 如果GCLocker活跃且需要GC,尝试扩展年轻代
        if (GCLocker::is_active_and_needs_gc() && policy()->can_expand_young_list()) {
          result = _allocator->attempt_allocation_force(word_size);
          if (result != NULL) {
            return result;
          }
        }
      }

      // 判断是否应该尝试GC(GCLocker没有要求等待GC)
      should_try_gc = !GCLocker::needs_gc();
      gc_count_before = total_collections();
    }

    if (should_try_gc) {
      GCCause::Cause gc_cause = preventive_collection_required ? GCCause::_g1_preventive_collection
                                                              : GCCause::_g1_inc_collection_pause;
      bool succeeded;
      // 这里会触发GC
      result = do_collection_pause(word_size, gc_count_before, &succeeded, gc_cause);
      if (result != NULL) {
        log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
                             Thread::current()->name(), p2i(result));
        return result;
      }

      if (succeeded) {
        log_trace(gc, alloc)("%s: Successfully scheduled collection failing to allocate "
                             SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
    } else {
      // GCLocker阻止GC,等待它清除
      if (gclocker_retry_count > GCLockerRetryAllocationCount) {
        log_warning(gc, alloc)("%s: Retried waiting for GCLocker too often allocating "
                               SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
      GCLocker::stall_until_clear();
      gclocker_retry_count += 1;
    }

    // 在尝试下一次循环前再试一次快速分配
    size_t dummy = 0;
    result = _allocator->attempt_allocation(word_size, word_size, &dummy);
    if (result != NULL) {
      return result;
    }
    // ... 警告日志等
  }
}

关键点

  • 函数在一个循环中多次尝试分配,避免频繁进入GC。

  • 持有Heap_lock后再次尝试分配,如果成功直接返回。

  • 考虑预防性GCpreventive_collection_required)和GCLocker机制(当JNI代码在临界区时阻止GC)。

  • 当确定需要GC时,调用do_collection_pause触发一次年轻代收集(或预防性收集)。

2.3 触发GC:do_collection_pause 与 VM_G1CollectForAllocation

do_collection_pause函数定义如下:

cpp

HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
                                               uint gc_count_before,
                                               bool* succeeded,
                                               GCCause::Cause gc_cause) {
  assert_heap_not_locked_and_not_at_safepoint();
  VM_G1CollectForAllocation op(word_size,
                               gc_count_before,
                               gc_cause,
                               policy()->max_pause_time_ms());
  VMThread::execute(&op);

  HeapWord* result = op.result();
  bool ret_succeeded = op.prologue_succeeded() && op.gc_succeeded();
  assert(result == NULL || ret_succeeded,
         "the result should be NULL if the VM did not succeed");
  *succeeded = ret_succeeded;

  assert_heap_not_locked();
  return result;
}

这里创建了一个VM_G1CollectForAllocation对象,它是一个VM_Operation的子类,封装了GC请求所需的参数(分配大小、GC计数、原因、最大停顿时间等)。然后调用VMThread::execute(&op)提交给VMThread执行。

VMThread::execute是连接Java线程和VMThread的关键桥梁,我们将在后续章节详细分析。执行完成后,通过op.result()获取分配到的内存地址(如果GC成功且有空闲内存),否则返回NULL。

至此,Java线程完成了从分配失败到提交GC请求的过程。接下来,我们看看VMThread是如何创建、运行并执行这些请求的。


3. VMThread:JVM的后台工作线程

VMThread是JVM内部一个特殊的线程,负责执行VM操作(VM_Operation)。它不存在于Java层,而是由JVM启动时创建并一直运行直到JVM关闭。

3.1 VMThread的创建与启动(Threads::create_vm

在JVM启动过程中,Threads::create_vm函数负责初始化各种子系统并创建VMThread。从用户提供的源码片段中可以看到相关代码:

cpp

// 在Threads::create_vm中,创建VMThread对象
{ TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime));

  VMThread::create(); // 创建VMThread对象
  Thread* vmthread = VMThread::vm_thread();

  if (!os::create_thread(vmthread, os::vm_thread)) {
    vm_exit_during_initialization("Cannot create VM thread. "
                                  "Out of system resources.");
  }

  // Wait for the VM thread to become ready, and VMThread::run to initialize
  {
    MonitorLocker ml(Notify_lock);
    os::start_thread(vmthread); // 启动线程
    while (vmthread->active_handles() == NULL) {
      ml.wait();
    }
  }
}

VMThread::create()函数(也位于源码片段中)负责:

  • 创建VMThread的C++对象(new VMThread())。

  • 如果启用了AbortVMOnVMOperationTimeout,创建超时监控任务VMOperationTimeoutTask

  • 初始化_terminate_lock互斥锁。

  • 创建性能计数器(如果启用PerfData)。

接着,通过os::create_thread创建一个操作系统原生线程(设置类型为os::vm_thread),然后调用os::start_thread启动该线程。启动后,等待VMThread设置其active_handles(表示它已经准备好接受操作),然后继续JVM启动的其余步骤。

3.2 VMThread的生命周期:run() -> loop() -> wait_for_operation()

VMThread启动后,其入口函数是VMThread::run()(在vmThread.cpp中):

cpp

void VMThread::run() {
  assert(this == vm_thread(), "check");

  // 分配JNI句柄块
  this->set_active_handles(JNIHandleBlock::allocate_block());

  {
    MutexLocker ml(Notify_lock);
    Notify_lock->notify();  // 通知创建者线程已经就绪
  }

  // 设置线程优先级
  int prio = (VMThreadPriority == -1)
    ? os::java_to_os_priority[NearMaxPriority]
    : VMThreadPriority;
  os::set_native_priority(this, prio);

  // 核心循环:处理VM操作直到终止
  this->loop();

  // 终止前的清理工作
  // ...
}

run()设置好句柄块、优先级后,调用loop()进入主循环。loop()的简化版本如下:

cpp

void VMThread::loop() {
  assert(_cur_vm_operation == NULL, "no current one should be executing");

  SafepointSynchronize::init(_vm_thread);

  // 准备一些默认操作
  cleanup_op.set_calling_thread(_vm_thread);
  safepointALot_op.set_calling_thread(_vm_thread);

  while (true) {
    if (should_terminate()) break;
    wait_for_operation();          // 等待有操作可执行
    if (should_terminate()) break;
    assert(_next_vm_operation != NULL, "Must have one");
    inner_execute(_next_vm_operation); // 执行操作
  }
}

循环的核心是wait_for_operation()inner_execute()

wait_for_operation()负责等待新的VM操作到达。如果当前没有待处理的操作,VMThread会进入睡眠(或周期性检查),直到被其他线程通过notify唤醒。

3.3 wait_for_operation():等待机制与安全点

下面是wait_for_operation()的代码片段:

cpp

void VMThread::wait_for_operation() {
  assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
  MonitorLocker ml_op_lock(VMOperation_lock, Mutex::_no_safepoint_check_flag);

  // 清除之前的操作
  _next_vm_operation = NULL;
  ml_op_lock.notify_all();

  while (!should_terminate()) {
    self_destruct_if_needed();
    if (_next_vm_operation != NULL) {
      return;
    }
    if (handshake_alot()) {
      // 执行握手操作
      // ...
    }
    assert(_next_vm_operation == NULL, "Must be");
    assert(_cur_vm_operation  == NULL, "Must be");

    setup_periodic_safepoint_if_needed();
    if (_next_vm_operation != NULL) {
      return;
    }

    ml_op_lock.notify_all();
    // 用户添加的调试打印(yym-gaizao)
    safe_print("VMThread::wait\n");
    ml_op_lock.wait(GuaranteedSafepointInterval);
  }
}
  • VMOperation_lock是保护操作队列的锁。

  • 清空_next_vm_operation(上一个操作已被执行),然后等待其他线程设置新的操作。

  • 如果handshake_alot()条件成立,可能会执行一些握手操作(调试用途)。

  • setup_periodic_safepoint_if_needed()用于在长时间没有操作时强制进入安全点,避免某些线程一直处于不安全状态。

  • 最后调用ml_op_lock.wait(GuaranteedSafepointInterval),让VMThread睡眠一段时间(默认是GuaranteedSafepointInterval毫秒),或者直到被notify唤醒。

当其他线程调用VMThread::execute并设置了_next_vm_operation后,会调用ml_op_lock.notify_all(),唤醒VMThread,然后VMThread发现_next_vm_operation != NULL,退出wait_for_operation(),进入inner_execute()执行真正的操作。


4. Java线程与VMThread的交互:执行GC操作

4.1 VMThread::execute 流程

VMThread::execute是Java线程提交操作的入口:

cpp

void VMThread::execute(VM_Operation* op) {
  Thread* t = Thread::current();

  // 如果当前线程就是VMThread,直接执行(避免递归)
  if (t->is_VM_thread()) {
    op->set_calling_thread(t);
    ((VMThread*)t)->inner_execute(op);
    return;
  }

  // 避免递归的GC-a-lot
  SkipGCALot sgcalot(t);

  // 如果是Java线程,检查安全点状态是否合法
  if (t->is_Java_thread()) {
    t->as_Java_thread()->check_for_valid_safepoint_state();
  }

  // 执行操作的前置钩子(prologue),如果返回false则取消操作
  if (!op->doit_prologue()) {
    return;
  }

  op->set_calling_thread(t);

  // 等待操作被执行(核心阻塞点)
  wait_until_executed(op);

  // 执行后置钩子(epilogue)
  op->doit_epilogue();
}
  • 如果调用线程已经是VMThread(比如VMThread内部又需要执行另一个VM操作,虽然很少见),则直接同步执行。

  • 普通Java线程会先调用doit_prologue()做一些准备工作(例如检查操作是否允许),然后进入wait_until_executed(op)

  • wait_until_executed会阻塞当前Java线程,直到VMThread处理完该操作。

4.2 wait_until_executed 的细节:安装操作、等待完成

wait_until_executed函数(源码片段提供)展示了如何将操作安装到VMThread并等待其完成:

cpp

void VMThread::wait_until_executed(VM_Operation* op) {
  MonitorLocker ml(VMOperation_lock,
                   Thread::current()->is_Java_thread() ?
                     Mutex::_safepoint_check_flag :
                     Mutex::_no_safepoint_check_flag);
  {
    TraceTime timer("Installing VM operation", TRACETIME_LOG(Trace, vmthread));
    while (true) {
      if (VMThread::vm_thread()->set_next_operation(op)) {
        // 用户添加的调试打印(yym-gaizao),输出当前线程名称和ID
        char buf[256];
        char threadNameBuf[64];
        get_current_thread_name(threadNameBuf, sizeof(threadNameBuf));
        int len = snprintf(buf, sizeof(buf), "JAVAThread::notify %s (id=%ld) \n", threadNameBuf, (long)os::current_thread_id());
        if (len > 0 && len < (int)sizeof(buf)) {
          safe_print(buf);
        } else {
          safe_print("Thread::notify\n");
        }
        ml.notify_all();   // 唤醒VMThread
        break;
      }
      // 如果当前已有其他操作在等待(_next_vm_operation不为NULL),则等待
      log_trace(vmthread)("A VM operation already set, waiting");
      ml.wait();
    }
  }
  {
    TraceTime timer("Waiting for VM operation to be completed", TRACETIME_LOG(Trace, vmthread));
    // 等待直到当前操作被执行完毕(_next_vm_operation不再指向op)
    while (_next_vm_operation == op) {
      ml.wait();
    }
  }
}

这里使用了VMOperation_lock来同步。关键步骤:

  1. 安装操作:调用set_next_operation(op)尝试将op设置为VMThread的下一个操作(_next_vm_operation)。成功返回true,否则返回false(表示已经有其他操作排队)。

  2. 如果安装成功,则调用ml.notify_all()唤醒可能正在wait_for_operation()中睡眠的VMThread。

  3. 然后进入第二个循环,等待_next_vm_operation != op,即操作已被VMThread取出并执行(或者被取消)。

  4. 当操作完成后,Java线程从wait_until_executed返回,继续执行doit_epilogue()

需要注意的是,VMOperation_lock在等待期间会释放锁,允许VMThread获取锁并处理操作。

4.3 线程名称获取的辅助函数

在用户添加的调试打印中,调用了get_current_thread_name函数,它通过pthread_getname_np获取当前线程的名称(Linux下)。源码中给出了该函数的实现:

cpp

bool get_current_thread_name(char* buf, size_t bufsize) {
    if (buf == NULL || bufsize == 0) return false;
    if (pthread_getname_np(pthread_self(), buf, bufsize) != 0) {
        snprintf(buf, bufsize, "unknown");
        return false;
    }
    buf[bufsize-1] = '\0';
    return true;
}

pthread_getname_np是非标准但广泛支持的扩展,用于获取POSIX线程的名称。在JVM中,Java线程会通过Thread::set_name设置原生线程名,因此该函数有助于在日志中区分是哪个Java线程触发了GC。


5. 完整流程梳理:从分配失败到GC完成

现在我们将所有片段串联起来,描述一次完整的分配失败触发GC的过程。

5.1 时间线图

text

Java线程                               VMThread
    |                                     |
    | 1. 调用 G1CollectedHeap::attempt_allocation
    |    -> attempt_allocation_slow
    |    -> do_collection_pause
    |    -> new VM_G1CollectForAllocation
    |    -> VMThread::execute(&op)
    |    -> wait_until_executed
    |        - 设置 _next_vm_operation = op
    |        - ml.notify_all() ------------> 唤醒
    |        - 进入等待状态                 |
    |                                     |
    |                                    2. wait_for_operation被唤醒
    |                                        - 发现 _next_vm_operation != NULL
    |                                        - 调用 inner_execute(op)
    |                                        - op->doit() 执行GC
    |                                        - 清除 _next_vm_operation
    |                                        - 退出 inner_execute
    |                                        - 再次进入 wait_for_operation
    |                                        - 设置 _next_vm_operation = NULL
    |                                        - ml_op_lock.notify_all()  (唤醒可能等待的操作)
    |                                     |
    | 3. 被 ml.notify() 唤醒(由于 _next_vm_operation != op)
    |    检查 while 条件退出
    |    返回结果
    |    执行 op->doit_epilogue()
    |    得到分配的内存地址
    v                                     v

5.2 关键代码片段串联

  1. Java线程分配对象:调用G1CollectedHeap::attempt_allocation -> 快速分配失败 -> attempt_allocation_slow

  2. 决定触发GC:在attempt_allocation_slow中,持有Heap_lock判断无法分配后,设置should_try_gc = true,然后调用do_collection_pause

  3. 构造VM操作do_collection_pause中创建VM_G1CollectForAllocation对象,调用VMThread::execute(&op)

  4. 提交操作VMThread::execute中,因为当前线程是Java线程,进入wait_until_executed(op)

    • wait_until_executed中,通过set_next_operation尝试安装操作。

    • 假设成功,调用ml.notify_all()唤醒VMThread。

    • 然后进入等待循环,等待_next_vm_operation不再等于op

  5. VMThread被唤醒:VMThread在wait_for_operation()中阻塞在ml_op_lock.wait上,被唤醒后检查_next_vm_operation,发现非空,退出等待。

  6. 执行操作:VMThread调用inner_execute(op),它会调用op->doit()执行实际的GC操作(在G1中会执行一次年轻代收集或混合收集)。

    • GC过程中可能会暂停所有Java线程(到达安全点),回收内存,并尝试分配所需对象。

    • 操作完成后,将结果(分配地址)保存在op的成员变量中,并清除_next_vm_operation

    • 最后,inner_execute返回,VMThread再次进入wait_for_operation循环。

  7. Java线程继续:由于_next_vm_operation已经被清除,Java线程在wait_until_executed的第二个循环中检测到条件不满足,退出等待,从VMThread::execute返回。

  8. 获取结果do_collection_pause通过op.result()得到内存地址,返回给上层attempt_allocation_slow,最终返回给Java线程的分配调用,完成对象分配。


6. 调试与日志:源码中的修改点

用户提供的源码片段中包含了自定义的调试信息,如safe_print("VMThread::wait\n")以及在线程唤醒时打印线程名称。这些修改有助于在实际运行中观察VMThread和Java线程的交互过程。例如,当一个Java线程因分配失败而触发GC时,控制台会输出类似:

text

JAVAThread::notify Worker-1 (id=12345) 
VMThread::wait

表明Worker-1线程通知了VMThread,VMThread正在等待操作。通过这样的日志,开发者可以跟踪GC的触发源和时序。


7. 总结与思考

本文基于OpenJDK 17源码,详细分析了Java线程在G1 GC下分配对象遇到内存不足时,如何通过VMThread::execute提交VM_G1CollectForAllocation操作,并阻塞等待;VMThread如何通过其事件循环接收操作、执行垃圾回收,最后将结果返回给Java线程的完整流程。

核心要点总结如下:

  • 分配与GC解耦:Java线程不直接执行GC,而是通过VM_Operation模式将请求转交给VMThread,避免复杂的并发控制。

  • 同步机制VMOperation_lockNotify_lock配合,实现了Java线程与VMThread之间的可靠通信和等待/通知语义。

  • 安全点:VMThread执行GC时必须让所有Java线程到达安全点,这通过safepoint.cpp中的协作机制完成(本文未深入但至关重要)。

  • 可扩展性:任何需要VM全局协调的操作(如线程转储、堆 dump、偏向锁批量撤销)都可以通过定义新的VM_Operation子类,并由VMThread::execute触发。

理解这一机制不仅有助于诊断JVM性能问题(如GC停顿、线程阻塞),还能为定制JVM或开发低延迟应用提供理论支持。希望读者通过本文的源码导览,能够对JVM内部的工作模型有更直观的认识。

##源码

void VMThread::create() {
  assert(vm_thread() == NULL, "we can only allocate one VMThread");
  _vm_thread = new VMThread();

  if (AbortVMOnVMOperationTimeout) {
    // Make sure we call the timeout task frequently enough, but not too frequent.
    // Try to make the interval 10% of the timeout delay, so that we miss the timeout
    // by those 10% at max. Periodic task also expects it to fit min/max intervals.
    size_t interval = (size_t)AbortVMOnVMOperationTimeoutDelay / 10;
    interval = interval / PeriodicTask::interval_gran * PeriodicTask::interval_gran;
    interval = MAX2<size_t>(interval, PeriodicTask::min_interval);
    interval = MIN2<size_t>(interval, PeriodicTask::max_interval);

    _timeout_task = new VMOperationTimeoutTask(interval);
    _timeout_task->enroll();
  } else {
    assert(_timeout_task == NULL, "sanity");
  }

  _terminate_lock = new Monitor(Mutex::safepoint, "VMThread::_terminate_lock", true,
                                Monitor::_safepoint_check_never);

  if (UsePerfData) {
    // jvmstat performance counters
    JavaThread* THREAD = JavaThread::current(); // For exception macros.
    _perf_accumulated_vm_operation_time =
                 PerfDataManager::create_counter(SUN_THREADS, "vmOperationTime",
                                                 PerfData::U_Ticks, CHECK);
  }
}

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
  extern void JDK_Version_init();

  // Preinitialize version info.
  VM_Version::early_initialize();

  // Check version
  if (!is_supported_jni_version(args->version)) return JNI_EVERSION;

  // Initialize library-based TLS
  ThreadLocalStorage::init();

  // Initialize the output stream module
  ostream_init();

  // Process java launcher properties.
  Arguments::process_sun_java_launcher_properties(args);

  // Initialize the os module
  os::init();

  MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite));

  // Record VM creation timing statistics
  TraceVmCreationTime create_vm_timer;
  create_vm_timer.start();

  // Initialize system properties.
  Arguments::init_system_properties();

  // So that JDK version can be used as a discriminator when parsing arguments
  JDK_Version_init();

  // Update/Initialize System properties after JDK version number is known
  Arguments::init_version_specific_system_properties();

  // Make sure to initialize log configuration *before* parsing arguments
  LogConfiguration::initialize(create_vm_timer.begin_time());

  // 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;

  // Final check of all ranges after ergonomics which may change values.
  if (!JVMFlagLimit::check_all_ranges()) {
    return JNI_EINVAL;
  }

  // Final check of all 'AfterErgo' constraints after ergonomics which may change values.
  bool constraint_result = JVMFlagLimit::check_all_constraints(JVMFlagConstraintPhase::AfterErgo);
  if (!constraint_result) {
    return JNI_EINVAL;
  }

  if (PauseAtStartup) {
    os::pause();
  }

  HOTSPOT_VM_INIT_BEGIN();

  // Timing (must come after argument parsing)
  TraceTime timer("Create VM", TRACETIME_LOG(Info, startuptime));

  // Initialize the os module after parsing the args
  jint os_init_2_result = os::init_2();
  if (os_init_2_result != JNI_OK) return os_init_2_result;

#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
  // Initialize assert poison page mechanism.
  if (ShowRegistersOnAssert) {
    initialize_assert_poison();
  }
#endif // CAN_SHOW_REGISTERS_ON_ASSERT

  SafepointMechanism::initialize();

  jint adjust_after_os_result = Arguments::adjust_after_os();
  if (adjust_after_os_result != JNI_OK) return adjust_after_os_result;

  // Initialize output stream logging
  ostream_init_log();

  // Convert -Xrun to -agentlib: if there is no JVM_OnLoad
  // Must be before create_vm_init_agents()
  if (Arguments::init_libraries_at_startup()) {
    convert_vm_init_libraries_to_agents();
  }

  // Launch -agentlib/-agentpath and converted -Xrun agents
  if (Arguments::init_agents_at_startup()) {
    create_vm_init_agents();
  }

  // Initialize Threads state
  _number_of_threads = 0;
  _number_of_non_daemon_threads = 0;

  // Initialize global data structures and create system classes in heap
  vm_init_globals();

#if INCLUDE_JVMCI
  if (JVMCICounterSize > 0) {
    JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtJVMCI);
    memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * JVMCICounterSize);
  } else {
    JavaThread::_jvmci_old_thread_counters = NULL;
  }
#endif // INCLUDE_JVMCI

  // Initialize OopStorage for threadObj
  _thread_oop_storage = OopStorageSet::create_strong("Thread OopStorage", mtThread);

  // Attach the main thread to this os thread
  JavaThread* main_thread = new JavaThread();
  main_thread->set_thread_state(_thread_in_vm);
  main_thread->initialize_thread_current();
  // must do this before set_active_handles
  main_thread->record_stack_base_and_size();
  main_thread->register_thread_stack_with_NMT();
  main_thread->set_active_handles(JNIHandleBlock::allocate_block());
  MACOS_AARCH64_ONLY(main_thread->init_wx());

  if (!main_thread->set_as_starting_thread()) {
    vm_shutdown_during_initialization(
                                      "Failed necessary internal allocation. Out of swap space");
    main_thread->smr_delete();
    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
    return JNI_ENOMEM;
  }

  // Enable guard page *after* os::create_main_thread(), otherwise it would
  // crash Linux VM, see notes in os_linux.cpp.
  main_thread->stack_overflow_state()->create_stack_guard_pages();

  // Initialize Java-Level synchronization subsystem
  ObjectMonitor::Initialize();
  ObjectSynchronizer::initialize();

  // Initialize global modules
  jint status = init_globals();
  if (status != JNI_OK) {
    main_thread->smr_delete();
    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
    return status;
  }

  JFR_ONLY(Jfr::on_create_vm_1();)

  // Should be done after the heap is fully created
  main_thread->cache_global_variables();

  { MutexLocker mu(Threads_lock);
    Threads::add(main_thread);
  }

  // Any JVMTI raw monitors entered in onload will transition into
  // real raw monitor. VM is setup enough here for raw monitor enter.
  JvmtiExport::transition_pending_onload_raw_monitors();

  // Create the VMThread
  { TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime));

    VMThread::create(); // 创建VMThread对象
    Thread* vmthread = VMThread::vm_thread();

    if (!os::create_thread(vmthread, os::vm_thread)) {
      vm_exit_during_initialization("Cannot create VM thread. "
                                    "Out of system resources.");
    }

    // Wait for the VM thread to become ready, and VMThread::run to initialize
    // Monitors can have spurious returns, must always check another state flag
    {
      MonitorLocker ml(Notify_lock);
      os::start_thread(vmthread); // 启动线程
      while (vmthread->active_handles() == NULL) {
        ml.wait();
      }
    }
  }

  assert(Universe::is_fully_initialized(), "not initialized");
  if (VerifyDuringStartup) {
    // Make sure we're starting with a clean slate.
    VM_Verify verify_op;
    VMThread::execute(&verify_op);
  }

  // We need this to update the java.vm.info property in case any flags used
  // to initially define it have been changed. This is needed for both CDS
  // since UseSharedSpaces may be changed after java.vm.info
  // is initially computed. See Abstract_VM_Version::vm_info_string().
  // This update must happen before we initialize the java classes, but
  // after any initialization logic that might modify the flags.
  Arguments::update_vm_info_property(VM_Version::vm_info_string());

  JavaThread* THREAD = JavaThread::current(); // For exception macros.
  HandleMark hm(THREAD);

  // Always call even when there are not JVMTI environments yet, since environments
  // may be attached late and JVMTI must track phases of VM execution
  JvmtiExport::enter_early_start_phase();

  // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
  JvmtiExport::post_early_vm_start();

  initialize_java_lang_classes(main_thread, CHECK_JNI_ERR);

  quicken_jni_functions();

  // No more stub generation allowed after that point.
  StubCodeDesc::freeze();

  // Set flag that basic initialization has completed. Used by exceptions and various
  // debug stuff, that does not work until all basic classes have been initialized.
  set_init_completed();

  LogConfiguration::post_initialize();
  Metaspace::post_initialize();

  HOTSPOT_VM_INIT_END();

  // record VM initialization completion time
#if INCLUDE_MANAGEMENT
  Management::record_vm_init_completed();
#endif // INCLUDE_MANAGEMENT

  // Signal Dispatcher needs to be started before VMInit event is posted
  os::initialize_jdk_signal_support(CHECK_JNI_ERR);

  // Start Attach Listener if +StartAttachListener or it can't be started lazily
  if (!DisableAttachMechanism) {
    AttachListener::vm_start();
    if (StartAttachListener || AttachListener::init_at_startup()) {
      AttachListener::init();
    }
  }

  // Launch -Xrun agents
  // Must be done in the JVMTI live phase so that for backward compatibility the JDWP
  // back-end can launch with -Xdebug -Xrunjdwp.
  if (!EagerXrunInit && Arguments::init_libraries_at_startup()) {
    create_vm_init_libraries();
  }

  Chunk::start_chunk_pool_cleaner_task();

  // Start the service thread
  // The service thread enqueues JVMTI deferred events and does various hashtable
  // and other cleanups.  Needs to start before the compilers start posting events.
  ServiceThread::initialize();

  // Start the monitor deflation thread:
  MonitorDeflationThread::initialize();

  // initialize compiler(s)
#if defined(COMPILER1) || COMPILER2_OR_JVMCI
#if INCLUDE_JVMCI
  bool force_JVMCI_intialization = false;
  if (EnableJVMCI) {
    // Initialize JVMCI eagerly when it is explicitly requested.
    // Or when JVMCILibDumpJNIConfig or JVMCIPrintProperties is enabled.
    force_JVMCI_intialization = EagerJVMCI || JVMCIPrintProperties || JVMCILibDumpJNIConfig;

    if (!force_JVMCI_intialization) {
      // 8145270: Force initialization of JVMCI runtime otherwise requests for blocking
      // compilations via JVMCI will not actually block until JVMCI is initialized.
      force_JVMCI_intialization = UseJVMCICompiler && (!UseInterpreter || !BackgroundCompilation);
    }
  }
#endif
  CompileBroker::compilation_init_phase1(CHECK_JNI_ERR);
  // Postpone completion of compiler initialization to after JVMCI
  // is initialized to avoid timeouts of blocking compilations.
  if (JVMCI_ONLY(!force_JVMCI_intialization) NOT_JVMCI(true)) {
    CompileBroker::compilation_init_phase2();
  }
#endif

  // Pre-initialize some JSR292 core classes to avoid deadlock during class loading.
  // It is done after compilers are initialized, because otherwise compilations of
  // signature polymorphic MH intrinsics can be missed
  // (see SystemDictionary::find_method_handle_intrinsic).
  initialize_jsr292_core_classes(CHECK_JNI_ERR);

  // This will initialize the module system.  Only java.base classes can be
  // loaded until phase 2 completes
  call_initPhase2(CHECK_JNI_ERR);

  JFR_ONLY(Jfr::on_create_vm_2();)

  // Always call even when there are not JVMTI environments yet, since environments
  // may be attached late and JVMTI must track phases of VM execution
  JvmtiExport::enter_start_phase();

  // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
  JvmtiExport::post_vm_start();

  // Final system initialization including security manager and system class loader
  call_initPhase3(CHECK_JNI_ERR);

  // cache the system and platform class loaders
  SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);

#if INCLUDE_CDS
  // capture the module path info from the ModuleEntryTable
  ClassLoader::initialize_module_path(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, tty);
    vm_exit_during_initialization("ClassLoader::initialize_module_path() failed unexpectedly");
  }
#endif

#if INCLUDE_JVMCI
  if (force_JVMCI_intialization) {
    JVMCI::initialize_compiler(CHECK_JNI_ERR);
    CompileBroker::compilation_init_phase2();
  }
#endif

  // Always call even when there are not JVMTI environments yet, since environments
  // may be attached late and JVMTI must track phases of VM execution
  JvmtiExport::enter_live_phase();

  // Make perfmemory accessible
  PerfMemory::set_accessible(true);

  // Notify JVMTI agents that VM initialization is complete - nop if no agents.
  JvmtiExport::post_vm_initialized();

  JFR_ONLY(Jfr::on_create_vm_3();)

#if INCLUDE_MANAGEMENT
  Management::initialize(THREAD);

  if (HAS_PENDING_EXCEPTION) {
    // management agent fails to start possibly due to
    // configuration problem and is responsible for printing
    // stack trace if appropriate. Simply exit VM.
    vm_exit(1);
  }
#endif // INCLUDE_MANAGEMENT

  StatSampler::engage();
  if (CheckJNICalls)                  JniPeriodicChecker::engage();

  BiasedLocking::init();

#if INCLUDE_RTM_OPT
  RTMLockingCounters::init();
#endif

  call_postVMInitHook(THREAD);
  // The Java side of PostVMInitHook.run must deal with all
  // exceptions and provide means of diagnosis.
  if (HAS_PENDING_EXCEPTION) {
    CLEAR_PENDING_EXCEPTION;
  }

  {
    MutexLocker ml(PeriodicTask_lock);
    // Make sure the WatcherThread can be started by WatcherThread::start()
    // or by dynamic enrollment.
    WatcherThread::make_startable();
    // Start up the WatcherThread if there are any periodic tasks
    // NOTE:  All PeriodicTasks should be registered by now. If they
    //   aren't, late joiners might appear to start slowly (we might
    //   take a while to process their first tick).
    if (PeriodicTask::num_tasks() > 0) {
      WatcherThread::start();
    }
  }

  create_vm_timer.end();
#ifdef ASSERT
  _vm_complete = true;
#endif

  if (DumpSharedSpaces) {
    MetaspaceShared::preload_and_dump();
    ShouldNotReachHere();
  }

  return JNI_OK;
}

void VMThread::run() {// jvm线程启动
  assert(this == vm_thread(), "check");

  // Notify_lock wait checks on active_handles() to rewait in
  // case of spurious wakeup, it should wait on the last
  // value set prior to the notify
  this->set_active_handles(JNIHandleBlock::allocate_block());

  {
    MutexLocker ml(Notify_lock);
    Notify_lock->notify();
  }
  // Notify_lock is destroyed by Threads::create_vm()

  int prio = (VMThreadPriority == -1)
    ? os::java_to_os_priority[NearMaxPriority]
    : VMThreadPriority;
  // Note that I cannot call os::set_priority because it expects Java
  // priorities and I am *explicitly* using OS priorities so that it's
  // possible to set the VM thread priority higher than any Java thread.
  os::set_native_priority( this, prio );

  // Wait for VM_Operations until termination
  this->loop();

  // Note the intention to exit before safepointing.
  // 6295565  This has the effect of waiting for any large tty
  // outputs to finish.
  if (xtty != NULL) {
    ttyLocker ttyl;
    xtty->begin_elem("destroy_vm");
    xtty->stamp();
    xtty->end_elem();
    assert(should_terminate(), "termination flag must be set");
  }

  // 4526887 let VM thread exit at Safepoint
  _cur_vm_operation = &halt_op;
  SafepointSynchronize::begin();

  if (VerifyBeforeExit) {
    HandleMark hm(VMThread::vm_thread());
    // Among other things, this ensures that Eden top is correct.
    Universe::heap()->prepare_for_verify();
    // Silent verification so as not to pollute normal output,
    // unless we really asked for it.
    Universe::verify();
  }

  CompileBroker::set_should_block();

  // wait for threads (compiler threads or daemon threads) in the
  // _thread_in_native state to block.
  VM_Exit::wait_for_threads_in_native_to_block();

  // The ObjectMonitor subsystem uses perf counters so do this before
  // we signal that the VM thread is gone. We don't want to run afoul
  // of perfMemory_exit() in exit_globals().
  ObjectSynchronizer::do_final_audit_and_print_stats();

  // signal other threads that VM process is gone
  {
    // Note: we must have the _no_safepoint_check_flag. Mutex::lock() allows
    // VM thread to enter any lock at Safepoint as long as its _owner is NULL.
    // If that happens after _terminate_lock->wait() has unset _owner
    // but before it actually drops the lock and waits, the notification below
    // may get lost and we will have a hang. To avoid this, we need to use
    // Mutex::lock_without_safepoint_check().
    MonitorLocker ml(_terminate_lock, Mutex::_no_safepoint_check_flag);
    _terminated = true;
    ml.notify();
  }

  // We are now racing with the VM termination being carried out in
  // another thread, so we don't "delete this". Numerous threads don't
  // get deleted when the VM terminates

}

void VMThread::wait_for_operation() {
  assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
  MonitorLocker ml_op_lock(VMOperation_lock, Mutex::_no_safepoint_check_flag);

  // Clear previous operation.
  // On first call this clears a dummy place-holder.
  _next_vm_operation = NULL;
  // Notify operation is done and notify a next operation can be installed.
  ml_op_lock.notify_all();

  while (!should_terminate()) {
    self_destruct_if_needed();
    if (_next_vm_operation != NULL) {
      return;
    }
    if (handshake_alot()) {
      {
        MutexUnlocker mul(VMOperation_lock);
        HandshakeALotClosure hal_cl;
        Handshake::execute(&hal_cl);
      }
      // When we unlocked above someone might have setup a new op.
      if (_next_vm_operation != NULL) {
        return;
      }
    }
    assert(_next_vm_operation == NULL, "Must be");
    assert(_cur_vm_operation  == NULL, "Must be");

    setup_periodic_safepoint_if_needed();
    if (_next_vm_operation != NULL) {
      return;
    }

    // We didn't find anything to execute, notify any waiter so they can install an op.
    ml_op_lock.notify_all();
    // yym-gaizao
    safe_print("VMThread::wait\n");
    ml_op_lock.wait(GuaranteedSafepointInterval);
  }
}

void VMThread::loop() {
  assert(_cur_vm_operation == NULL, "no current one should be executing");

  SafepointSynchronize::init(_vm_thread);

  // Need to set a calling thread for ops not passed
  // via the normal way.
  cleanup_op.set_calling_thread(_vm_thread);
  safepointALot_op.set_calling_thread(_vm_thread);

  while (true) {
    if (should_terminate()) break;
    wait_for_operation();
    if (should_terminate()) break;
    assert(_next_vm_operation != NULL, "Must have one");
    inner_execute(_next_vm_operation);
  }
}

int
__pthread_getname_np (pthread_t th, char *buf, size_t len)
{
  const struct pthread *pd = (const struct pthread *) th;

  /* Unfortunately the kernel headers do not export the TASK_COMM_LEN
     macro.  So we have to define it here.  */
#define TASK_COMM_LEN 16
  if (len < TASK_COMM_LEN)
    return ERANGE;

  if (pd == THREAD_SELF)
    return __prctl (PR_GET_NAME, buf) ? errno : 0;

#define FMT "/proc/self/task/%u/comm"
  char fname[sizeof (FMT) + 8];
  sprintf (fname, FMT, (unsigned int) pd->tid);

  int fd = __open64_nocancel (fname, O_RDONLY);
  if (fd == -1)
    return errno;

  int res = 0;
  ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, buf, len));
  if (n < 0)
    res = errno;
  else
    {
      if (buf[n - 1] == '\n')
	buf[n - 1] = '\0';
      else if (n == len)
	res = ERANGE;
      else
	buf[n] = '\0';
    }

  __close_nocancel_nostatus (fd);

  return res;
}
versioned_symbol (libc, __pthread_getname_np, pthread_getname_np,
		  GLIBC_2_34);


// 返回值:成功返回 true,失败返回 false
bool get_current_thread_name(char* buf, size_t bufsize) {
    if (buf == NULL || bufsize == 0) return false;
    if (pthread_getname_np(pthread_self(), buf, bufsize) != 0) {
        snprintf(buf, bufsize, "unknown");
        return false;
    }
    buf[bufsize-1] = '\0';
    return true;
}


void VMThread::wait_until_executed(VM_Operation* op) {
  MonitorLocker ml(VMOperation_lock,
                   Thread::current()->is_Java_thread() ?
                     Mutex::_safepoint_check_flag :
                     Mutex::_no_safepoint_check_flag);
  {
    TraceTime timer("Installing VM operation", TRACETIME_LOG(Trace, vmthread));
    while (true) {
      if (VMThread::vm_thread()->set_next_operation(op)) {
        // yym-gaizao
        char buf[256];
        char threadNameBuf[64];
        get_current_thread_name(threadNameBuf, sizeof(threadNameBuf));
        int len = snprintf(buf, sizeof(buf), "JAVAThread::notify %s (id=%ld) \n", threadNameBuf, (long)os::current_thread_id());
        if (len > 0 && len < (int)sizeof(buf)) {
          safe_print(buf);
        }else {
          safe_print("Thread::notify\n");
        }
        ml.notify_all();
        break;
      }
      // Wait to install this operation as the next operation in the VM Thread
      log_trace(vmthread)("A VM operation already set, waiting");
      ml.wait();
    }
  }
  {
    // Wait until the operation has been processed
    TraceTime timer("Waiting for VM operation to be completed", TRACETIME_LOG(Trace, vmthread));
    // _next_vm_operation is cleared holding VMOperation_lock after it has been
    // executed. We wait until _next_vm_operation is not our op.
    while (_next_vm_operation == op) {
      // VM Thread can process it once we unlock the mutex on wait.
      ml.wait();
    }
  }
}

void VMThread::execute(VM_Operation* op) {
  Thread* t = Thread::current();

  if (t->is_VM_thread()) {
    op->set_calling_thread(t);
    ((VMThread*)t)->inner_execute(op);
    return;
  }

  // Avoid re-entrant attempts to gc-a-lot
  SkipGCALot sgcalot(t);

  // JavaThread or WatcherThread
  if (t->is_Java_thread()) {
    t->as_Java_thread()->check_for_valid_safepoint_state();
  }

  // New request from Java thread, evaluate prologue
  if (!op->doit_prologue()) {
    return;   // op was cancelled
  }

  op->set_calling_thread(t);

  wait_until_executed(op);

  op->doit_epilogue();
}

HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
                                               uint gc_count_before,
                                               bool* succeeded,
                                               GCCause::Cause gc_cause) {
  assert_heap_not_locked_and_not_at_safepoint();
  VM_G1CollectForAllocation op(word_size,
                               gc_count_before,
                               gc_cause,
                               policy()->max_pause_time_ms());
  VMThread::execute(&op);

  HeapWord* result = op.result();
  bool ret_succeeded = op.prologue_succeeded() && op.gc_succeeded();
  assert(result == NULL || ret_succeeded,
         "the result should be NULL if the VM did not succeed");
  *succeeded = ret_succeeded;

  assert_heap_not_locked();
  return result;
}

HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
  ResourceMark rm; // For retrieving the thread names in log messages.

  // Make sure you read the note in attempt_allocation_humongous().

  assert_heap_not_locked_and_not_at_safepoint();
  assert(!is_humongous(word_size), "attempt_allocation_slow() should not "
         "be called for humongous allocation requests");

  // We should only get here after the first-level allocation attempt
  // (attempt_allocation()) failed to allocate.

  // We will loop until a) we manage to successfully perform the
  // allocation or b) we successfully schedule a collection which
  // fails to perform the allocation. b) is the only case when we'll
  // return NULL.
  HeapWord* result = NULL;
  for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
    bool should_try_gc;
    bool preventive_collection_required = false;
    uint gc_count_before;

    {
      MutexLocker x(Heap_lock);

      // Now that we have the lock, we first retry the allocation in case another
      // thread changed the region while we were waiting to acquire the lock.
      size_t actual_size;
      result = _allocator->attempt_allocation(word_size, word_size, &actual_size);
      if (result != NULL) {
        return result;
      }

      preventive_collection_required = policy()->preventive_collection_required(1);
      if (!preventive_collection_required) {
        // We've already attempted a lock-free allocation above, so we don't want to
        // do it again. Let's jump straight to replacing the active region.
        result = _allocator->attempt_allocation_using_new_region(word_size);
        if (result != NULL) {
          return result;
        }

        // If the GCLocker is active and we are bound for a GC, try expanding young gen.
        // This is different to when only GCLocker::needs_gc() is set: try to avoid
        // waiting because the GCLocker is active to not wait too long.
        if (GCLocker::is_active_and_needs_gc() && policy()->can_expand_young_list()) {
          // No need for an ergo message here, can_expand_young_list() does this when
          // it returns true.
          result = _allocator->attempt_allocation_force(word_size);
          if (result != NULL) {
            return result;
          }
        }
      }

      // Only try a GC if the GCLocker does not signal the need for a GC. Wait until
      // the GCLocker initiated GC has been performed and then retry. This includes
      // the case when the GC Locker is not active but has not been performed.
      should_try_gc = !GCLocker::needs_gc();
      // Read the GC count while still holding the Heap_lock.
      gc_count_before = total_collections();
    }

    if (should_try_gc) {
      GCCause::Cause gc_cause = preventive_collection_required ? GCCause::_g1_preventive_collection
                                                              : GCCause::_g1_inc_collection_pause;
      bool succeeded;
      // yym-gaizao
      char buf[256];
      char threadNameBuf[64];
      get_current_thread_name(threadNameBuf, sizeof(threadNameBuf));
      snprintf(buf, sizeof(buf), "small object do_collection_pause %s (id=%ld) \n", threadNameBuf, (long)os::current_thread_id());
      safe_print(buf);
      result = do_collection_pause(word_size, gc_count_before, &succeeded, gc_cause);
      if (result != NULL) {
        assert(succeeded, "only way to get back a non-NULL result");
        log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
                             Thread::current()->name(), p2i(result));
        return result;
      }

      if (succeeded) {
        // We successfully scheduled a collection which failed to allocate. No
        // point in trying to allocate further. We'll just return NULL.
        log_trace(gc, alloc)("%s: Successfully scheduled collection failing to allocate "
                             SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
      log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating " SIZE_FORMAT " words",
                           Thread::current()->name(), word_size);
    } else {
      // Failed to schedule a collection.
      if (gclocker_retry_count > GCLockerRetryAllocationCount) {
        log_warning(gc, alloc)("%s: Retried waiting for GCLocker too often allocating "
                               SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
      log_trace(gc, alloc)("%s: Stall until clear", Thread::current()->name());
      // The GCLocker is either active or the GCLocker initiated
      // GC has not yet been performed. Stall until it is and
      // then retry the allocation.
      GCLocker::stall_until_clear();
      gclocker_retry_count += 1;
    }

    // We can reach here if we were unsuccessful in scheduling a
    // collection (because another thread beat us to it) or if we were
    // stalled due to the GC locker. In either can we should retry the
    // allocation attempt in case another thread successfully
    // performed a collection and reclaimed enough space. We do the
    // first attempt (without holding the Heap_lock) here and the
    // follow-on attempt will be at the start of the next loop
    // iteration (after taking the Heap_lock).
    size_t dummy = 0;
    result = _allocator->attempt_allocation(word_size, word_size, &dummy);
    if (result != NULL) {
      return result;
    }

    // Give a warning if we seem to be looping forever.
    if ((QueuedAllocationWarningCount > 0) &&
        (try_count % QueuedAllocationWarningCount == 0)) {
      log_warning(gc, alloc)("%s:  Retried allocation %u times for " SIZE_FORMAT " words",
                             Thread::current()->name(), try_count, word_size);
    }
  }

  ShouldNotReachHere();
  return NULL;
}

inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size,
                                                     size_t desired_word_size,
                                                     size_t* actual_word_size) {
  assert_heap_not_locked_and_not_at_safepoint();
  assert(!is_humongous(desired_word_size), "attempt_allocation() should not "
         "be called for humongous allocation requests");

  HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size);

  if (result == NULL) {
    *actual_word_size = desired_word_size;
    result = attempt_allocation_slow(desired_word_size);
  }

  assert_heap_not_locked();
  if (result != NULL) {
    assert(*actual_word_size != 0, "Actual size must have been set here");
    dirty_young_block(result, *actual_word_size);
  } else {
    *actual_word_size = 0;
  }

  return result;
}

# if __GNUC_PREREQ (6, 0)
#  define THREAD_SELF \
  (*(struct pthread *__seg_fs *) offsetof (struct pthread, header.self))
# else
#  define THREAD_SELF \
  ({ struct pthread *__self;						      \
     asm ("mov %%fs:%c1,%0" : "=r" (__self)				      \
	  : "i" (offsetof (struct pthread, header.self)));	 	      \
     __self;})
# endif

pthread_t
__pthread_self (void)
{
  return (pthread_t) THREAD_SELF;
}
libc_hidden_def (__pthread_self)
weak_alias (__pthread_self, pthread_self)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐