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.