Android ART虚拟机中的线程管理(七)

一,线程的创建

在java代码中可以有多种方式创建一个线程,常用的方法是:

Thread thd = new Thread();

这个创建会调用init,init2初始化一个线程:

libcore/ojluni/src/main/java/java/lang/Thread.java

    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        Thread parent = currentThread();
        ...
        init2(parent);
        tid = nextThreadID();
    }
    private void init2(Thread parent) {
        this.contextClassLoader = parent.getContextClassLoader();
        this.inheritableThreadLocals = ThreadLocal.createInheritedMap(
                parent.inheritableThreadLocals);
    }

new 一个Thread对象,其实新线程并没有被创建出来,而是要等到Thread.start()被调用才会新起线程。

  public synchronized void start() {
        started = false;
        try {
            nativeCreate(this, stackSize, daemon);
            started = true;
        } finally {
        }
    }

通过nativeCreate(),java层的Thread类最终关联的是native层中的Thread.cc

art/runtime/Thread.cc

void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
  CHECK(java_peer != nullptr);
  Thread* self = static_cast<JNIEnvExt*>(env)->self;
  Runtime* runtime = Runtime::Current();
  // Atomically start the birth of the thread ensuring the runtime isn't shutting down.
  bool thread_start_during_shutdown = false;
  {
    MutexLock mu(self, *Locks::runtime_shutdown_lock_);
    if (runtime->IsShuttingDownLocked()) {
      thread_start_during_shutdown = true;
    } else {
      runtime->StartThreadBirth();
    }
  }

  Thread* child_thread = new Thread(is_daemon);
  
  // Try to allocate a JNIEnvExt for the thread. We do this here as we might be out of memory and
  // do not have a good way to report this on the child's side.
  std::unique_ptr<JNIEnvExt> child_jni_env_ext(
      JNIEnvExt::Create(child_thread, Runtime::Current()->GetJavaVM()));

  int pthread_create_result = 0;
  if (child_jni_env_ext.get() != nullptr) {
    pthread_t new_pthread;
    pthread_attr_t attr;
    child_thread->tlsPtr_.tmp_jni_env = child_jni_env_ext.get();
    CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), "new thread");
    CHECK_PTHREAD_CALL(pthread_attr_setdetachstate, (&attr, PTHREAD_CREATE_DETACHED),
                       "PTHREAD_CREATE_DETACHED");
    CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), stack_size);
    pthread_create_result = pthread_create(&new_pthread,
                                           &attr,
                                           Thread::CreateCallback,
                                           child_thread);
    CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "new thread");
  }

  // Either JNIEnvExt::Create or pthread_create(3) failed, so clean up.
  {
    MutexLock mu(self, *Locks::runtime_shutdown_lock_);
    runtime->EndThreadBirth();
  }
}

StartThreadBirth,EndThreadBirth是配套使用的,表示当前有新线程在孵化中。

接下来通过Thread* child_thread = new Thread(is_daemon);创建一个新的线程类,但是真正fork一个线程的地方,还是系统调用pthread_create函数。

bionic/libc/bionic/Pthread_create.cpp

int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
                   void* (*start_routine)(void*), void* arg) {
}

其中第一个参数是指向线程标志符的指针;第二个参数线程的属性值;第三个参数是新线程的入口地址;第四个参数是新线程入口函数所需的参数。

art/runtime/Thread.cc

void* Thread::CreateCallback(void* arg) {
  Thread* self = reinterpret_cast<Thread*>(arg);
  Runtime* runtime = Runtime::Current();
  {
    // Note: given that the JNIEnv is created in the parent thread, the only failure point here is
    //       a mess in InitStackHwm. We do not have a reasonable way to recover from that, so abort
    //       the runtime in such a case. In case this ever changes, we need to make sure here to
    //       delete the tmp_jni_env, as we own it at this point.
    CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM(), self->tlsPtr_.tmp_jni_env));
    self->tlsPtr_.tmp_jni_env = nullptr;
    Runtime::Current()->EndThreadBirth();
  }
  {
    // Invoke the 'run' method of our java.lang.Thread.
    mirror::Object* receiver = self->tlsPtr_.opeer;
    jmethodID mid = WellKnownClasses::java_lang_Thread_run;
    ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
    InvokeVirtualOrInterfaceWithJValues(soa, ref.get(), mid, nullptr);
  }
  // Detach and delete self.
  Runtime::Current()->GetThreadList()->Unregister(self);
  return nullptr;
}

其中的参数arg就是CreateNativeThread()中的创建的Thread类对象,CreateCallback这个函数执行完,一个新的线程就起来了。

这个函数主要做了那些事情?

1)self->init的调用,将其纳入虚拟机的统一管理。

2)准备函数InvokeVirtualOrInterfaceWithJValues需要的参数,其中的参数mid表示java函数的ID号,这里的赋值是:jmethodID mid = WellKnownClasses::java_lang_Thread_run;也就是Thread的run方法。WellKnownClasses这个类是一个基础类,他会通过进一步的调用通过ClassLinker来完成函数的查找。

3)执行新线程承载任务的代码,也就是在native层调用并执行java层中的run函数,这个CreateCallBack是怎么找到run函数对应的代码的?这就是InvokeVirtualOrInterfaceWithJValues完成的工作。

art/runtime/Reflection.cc

JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject obj, jmethodID mid, jvalue* args) {
  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
  ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
  if (is_string_init) {
    // Replace calls to String.<init> with equivalent StringFactory call.
    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
    receiver = nullptr;
  }
  uint32_t shorty_len = 0;
  const char* shorty = method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty(&shorty_len);
  JValue result;
  ArgArray arg_array(shorty, shorty_len);
  arg_array.BuildArgArrayFromJValues(soa, receiver, args);
  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
  return result;
}

通过FindVirtualMethod查找到正确的artMethod,ArtMethod是虚拟机内部对函数的描述。然后调用InvokeWithArgArray执行查找到的函数。


二,线程的挂起

比如在执行GC时,通常需要把所有线程挂起。

art/runtime/Thread_list.cc

void ThreadList::SuspendAll(const char* cause, bool long_suspend) {
  Thread* self = Thread::Current();
  {
    ScopedTrace trace("Suspending mutator threads");
    const uint64_t start_time = NanoTime();

    SuspendAllInternal(self, self);
    // All threads are known to have suspended (but a thread may still own the mutator lock)
    // Make sure this thread grabs exclusive access to the mutator lock and its protected data.
#if HAVE_TIMED_RWLOCK
    while (true) {
      if (Locks::mutator_lock_->ExclusiveLockWithTimeout(self, kThreadSuspendTimeoutMs, 0)) {
        break;
      } else if (!long_suspend_) {
        // Reading long_suspend without the mutator lock is slightly racy, in some rare cases, this
        // could result in a thread suspend timeout.
        // Timeout if we wait more than kThreadSuspendTimeoutMs seconds.
        UnsafeLogFatalForThreadSuspendAllTimeout();
      }
    }
#else
    Locks::mutator_lock_->ExclusiveLock(self);
#endif

    long_suspend_ = long_suspend;
    const uint64_t end_time = NanoTime();
    const uint64_t suspend_time = end_time - start_time;
    suspend_all_historam_.AdjustAndAddValue(suspend_time);
  }
}

Thread_list是当前虚拟机中管理的线程的集合,SuspendAllInternal会挂起所有运行着的线程,没有运行的线程不要启动。

做法是给各个线程设置suspend-reques flag使其进入挂起状态,也即是kSuspendRequest,这个判断线程是否挂起的函数中一个参考值。

对线程挂起的管理主要利用mutator_lock控制,这是一个读写锁。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深入理解Android虚拟机ART,需要对ART的原理、架构和功能进行全面的了解。 ARTAndroid Runtime)是Android操作系统的一种虚拟机,它在Android 5.0及以后的版本取代了Dalvik虚拟机ART通过对应用程序的预编译,将字节码转换为机器码,提供了更高的性能和更低的内存占用。 ART的内部架构由多个模块组成,包括编译器、运行时库和垃圾回收器。编译器模块负责将应用程序的字节码转换为本地机器码,采用了提前编译(Ahead-of-Time Compilation)的方式,将代码的热点部分提前编译为本地机器码,从而加速应用程序的执行。运行时库模块提供了与设备硬件和操作系统交互的接口,同时实现了一些Java虚拟机的功能,如线程管理和异常处理。垃圾回收器模块负责管理内存资源,通过回收不再使用的对象,提供了更好的内存管理能力。 ART提供了一些新的特性,如增强的垃圾回收、即时编译和应用程序优化等。其,增强的垃圾回收机制使用了新的分代垃圾回收算法,能更好地管理内存资源,减少应用程序的内存占用。即时编译(Just-In-Time Compilation)可以将应用程序的热点代码实时编译为机器码,在应用程序的执行过程提升性能。应用程序优化功能可以分析应用程序的运行状况,根据实际情况进行优化,提供更好的用户体验。 总之,深入理解Android虚拟机ART需要详细了解其原理、架构和功能,同时还需要研究相关的性能优化方法和工具。只有全面了解ART,才能更好地开发和优化Android应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值