Face bottom first stop – On Thread (Thread size)

  • Thread size (part 1)
  • JNIEnv what does JNIEnv do?
  • Monitor(art/runtime/monitor.cc) (下)

Method stack size

The init method is called in the Thread constructor, and the fourth long parameter indicates the stack size, which is usually 0 (the default is specified by the system).

private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
	...
}
Copy the code

The thread is started, and nativeCreate is propagated to the bottom layer when start is called

public synchronized void start() { ... nativeCreate(this, stackSize, daemon); . }Copy the code

NativeCreate is called by JNI to the CreateNativeThread of Thread. cc

void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) { // 1. Stack_size = FixStackSize(stack_size); stack_size = FixStackSize(stack_size); pthread_attr_t attr; / / call to bionic/libc/bionic/pthread_attr CPP pthread_attr_setstacksize / / attr - > stack_size = stack_size; // Set stack_size to attr CHECK_PTHREAD_CALL(pthread_attr_setStackSize, (&attr, stack_size), stack_size); Pthread_create_result = pthread_create(&new_pthread, &attr, Thread::CreateCallback, child_thread); }Copy the code

Note 1. Method stack size Settings

Static size_t FixStackSize(size_t stack_size) {if (stack_size == 0) {// Stack_size = 0 Runtime::Current()->GetDefaultStackSize(); } // 1M stack_size += 1 * MB; . Stack_size = RoundUp(stack_size, kPageSize); return stack_size; }Copy the code

GDB debugging can see stack_size results

Note 2. Thread creation

bionic/libc/bionic/pthread_create.cpp

int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr, void* (*start_routine)(void*), void* arg) { pthread_attr_t thread_attr; thread_attr = *attr; attr = NULL; // Prevent misuse below. pthread_internal_t* thread = NULL; void* child_stack = NULL; Int result = __allocate_thread(&thread_attr, &thread_attr, &child_stack); if (result ! = 0) { return result; }}Copy the code

Note 3. Allocating memory TLS initialization

static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) { size_t mmap_size; uint8_t* stack_top; if (attr->stack_base == NULL) { if (__builtin_add_overflow(attr->stack_size, attr->guard_size, &mmap_size)) return EAGAIN; if (__builtin_add_overflow(mmap_size, sizeof(pthread_internal_t), &mmap_size)) return EAGAIN; mmap_size = __BIONIC_ALIGN(mmap_size, PAGE_SIZE); attr->guard_size = __BIONIC_ALIGN(attr->guard_size, PAGE_SIZE); Attr ->stack_base = __create_thread_mapped_space(mmap_size, attr->guard_size); if (attr->stack_base == NULL) { return EAGAIN; } stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + mmap_size; }... Stack_top = reinterpret_cast<uint8_t*>( (reinterpret_cast<uintptr_t>(stack_top) - sizeof(pthread_internal_t)) & ~0xf); pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top); if (mmap_size == 0) { memset(thread, 0, sizeof(pthread_internal_t)); } // Update stack_zise attr->stack_size = stack_top - reinterpret_cast<uint8_t*>(attr->stack_base); thread->mmap_size = mmap_size; thread->attr = *attr; //4. Initialize thread-local storage TLS if (! __init_tls(thread)) { if (thread->mmap_size ! = 0) munmap(thread->attr.stack_base, thread->mmap_size); return EAGAIN; } __init_thread_stack_guard(thread); *threadp = thread; *child_stack = stack_top; return 0; }Copy the code

Note 4. Local temporary storage TLS initialization

bool __init_tls(pthread_internal_t* thread) { thread->tls[TLS_SLOT_SELF] = thread->tls; thread->tls[TLS_SLOT_THREAD_ID] = thread; // Local temporary storage TLS size 20K (20480b) size_t allocation_size = BIONIC_TLS_SIZE + (2 * PTHREAD_GUARD_SIZE); void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (allocation == MAP_FAILED) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: couldn't allocate TLS: %s", strerror(errno)); return false; } prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard"); thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PTHREAD_GUARD_SIZE); if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) ! = 0) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: couldn't mprotect TLS: %s", strerror(errno)); munmap(allocation, allocation_size); return false; } prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS"); return true; }Copy the code

Calculation of Thread size

The size of a Java Thread object is about 132b, and the size of a Java Thread object is at least 180B

Size of Thread: stack (1M+16K)+ TLS(20K)+ size of Thread object (180B)

(ps: the object size of c++ thread (including monitor and other members) is not calculated.)

It is worth mentioning that MMAP allocates virtual memory and does not allocate physical memory. When it is used, Linux will only allocate physical memory due to the interruption of missing pages.

GDB has been tested for a long time.