当前位置: 首页 > news >正文

佛山网站建设专业现状昆明网站建站平台

佛山网站建设专业现状,昆明网站建站平台,保定网络营销推广,网站建设尽量近期处理Bugly上OOM问题#xff0c;很多发生在Thread创建启动过程#xff0c;虽然最后分析出是32位4G虚拟内存不足导致#xff0c;但还是分析下Java层Thread 源码过程#xff0c;可能会抛出的异常InternalError/Out of memory。 Thread报错堆栈#xff1a; Java线程创建…近期处理Bugly上OOM问题很多发生在Thread创建启动过程虽然最后分析出是32位4G虚拟内存不足导致但还是分析下Java层Thread 源码过程可能会抛出的异常InternalError/Out of memory。 Thread报错堆栈 Java线程创建到启动过程 从Thread.start()- c层CreateNativeThread()-JNIEnvExt::Create()创建JniEnv -c层pthread_create()— allocate_thread()分配堆内存-Linux层clone()拷贝新线程- 反射调用Thread.run() 源码分析 Java层Thread#start(): 接着来到c层 http://aospxref.com/android-7.1.2_r39/xref/art/runtime/native/java_lang_Thread.cc /art/runtime/native/java_lang_Thread.cc static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,jboolean daemon) {//... 部分zygote进程是不允许创建线程,会抛出InternalError异常//接下来看Thread::CreateNativeThread(env, java_thread, stack_size, daemon JNI_TRUE); }http://aospxref.com/android-7.1.2_r39/xref/art/runtime/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_castJNIEnvExt*(env)-self;//若当虚拟机正在关闭时,创建线程会抛出InternalError异常Runtime* runtime Runtime::Current();bool thread_start_during_shutdown false;{MutexLock mu(self, *Locks::runtime_shutdown_lock_);if (runtime-IsShuttingDownLocked()) {thread_start_during_shutdown true;} else {runtime-StartThreadBirth();}}if (thread_start_during_shutdown) {ScopedLocalRefjclass error_class(env, env-FindClass(java/lang/InternalError));env-ThrowNew(error_class.get(), Thread starting during runtime shutdown);return;}Thread* child_thread new Thread(is_daemon);//创建java层thread对应的c对象child_thread-tlsPtr_.jpeer env-NewGlobalRef(java_peer); // 将java层的Thread引用创建成全局引用stack_size FixStackSize(stack_size);// 计算出线程的堆内存大小,默认计算出是1040kb//将线程记录在线程组中env-SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer,reinterpret_castjlong(child_thread));//给c层Threa对象创建JNIEnvExt环境(一个线程对应一个jniEnv),这一步可能会OOMstd::unique_ptrJNIEnvExt child_jni_env_ext(JNIEnvExt::Create(child_thread, Runtime::Current()-GetJavaVM()));int pthread_create_result 0;if (child_jni_env_ext.get() ! nullptr) {// 闯将线程的JniEnv成功时pthread_t new_pthread;pthread_attr_t attr;child_thread-tlsPtr_.tmp_jni_env child_jni_env_ext.get();//将JniEnv赋值给C层Thread对象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);//真正创建线程,参数1是线程标识符参数2线程属性设置(设置堆的大小等等)参数3线程函数的起始地址参数4传递给参数3线程函数的参数pthread_create_result pthread_create(new_pthread,attr,Thread::CreateCallback,child_thread);CHECK_PTHREAD_CALL(pthread_attr_destroy, (attr), new thread);if (pthread_create_result 0) { // 若是线程创建,执行完Java层Thread#run()后会返回0child_jni_env_ext.release();return; // 释放执行完成任务的线程资源不会往下走}}//当创建失败时,释放资源env-DeleteGlobalRef(child_thread-tlsPtr_.jpeer); //删除java层的thread 全局引用child_thread-tlsPtr_.jpeer nullptr;delete child_thread; //删除 c层Thread指针child_thread nullptr;//从线程组中移除env-SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0);//当创建线程的JniEnv失败或者pthread_create创建线程失败时会抛出异常{std::string msg(child_jni_env_ext.get() nullptr ?Could not allocate JNI Env : //当线程创建JniEnv 环境失败时抛出该提示语StringPrintf(pthread_create (%s stack) failed: %s,PrettySize(stack_size).c_str(), strerror(pthread_create_result)));ScopedObjectAccess soa(env);soa.Self()-ThrowOutOfMemoryError(msg.c_str()); //抛出OOM 异常} }通过FixStackSize()计算出线程的堆内存大小,堆内存1024K(1M)8k8K1040k static size_t FixStackSize(size_t stack_size) { //参数是java层中thread 的stack_size默认0if (stack_size 0) {// GetDefaultStackSize 是启动art时命令行的 -Xss 参数, Android 中没有该参数因此为0.stack_size Runtime::Current()-GetDefaultStackSize();}// bionic pthread 默认栈大小是 1Mstack_size 1 * MB;//...if (Runtime::Current()-ExplicitStackOverflowChecks()) {//8kstack_size GetStackOverflowReservedBytes(kRuntimeISA);} else {8k8Kstack_size Thread::kStackOverflowImplicitCheckSize GetStackOverflowReservedBytes(kRuntimeISA);}//...return stack_size;}查看创建JniEnv过程 http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_env_ext.cc /art/runtime/jni_env_ext.cc JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in) {std::unique_ptrJNIEnvExt ret(new JNIEnvExt(self_in, vm_in));if (CheckLocalsValid(ret.get())) {return ret.release();}return nullptr; }JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in): self(self_in),vm(vm_in),local_ref_cookie(IRT_FIRST_SEGMENT),locals(kLocalsInitial, kLocalsMax, kLocal, false),check_jni(false),runtime_deleted(false),critical(0),monitors(monitors, kMonitorsInitial, kMonitorsMax) {functions unchecked_functions GetJniNativeInterface(); //获取到全局的Jni函数接口列表if (vm-IsCheckJniEnabled()) {SetCheckJniEnabled(true);} } 查看pthread的创建线程过程 http://aospxref.com/android-7.1.2_r39/xref/bionic/libc/bionic/pthread_create.cpp /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_internal_t* thread NULL;void* child_stack NULL;//创建线程的堆内存int result __allocate_thread(thread_attr, thread, child_stack);if (result ! 0) {return result; //若是创建失败,则抛出oom 异常}//.... int flags CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;//linux 的clone 进程,即int rc clone(__pthread_start, child_stack, flags, thread, (thread-tid), tls, (thread-tid));if (rc -1) {int clone_errno errno;if (thread-mmap_size ! 0) {//当拷贝失败时,释放申请好的匿名共享内存munmap(thread-attr.stack_base, thread-mmap_size);}// 当拷贝进程失败时会输出错误日志 clone faild__libc_format_log(ANDROID_LOG_WARN, libc, pthread_create failed: clone failed: %s, strerror(errno));return clone_errno;}//...return 0; }接下来看下__allocate_thread()是如何创建线程的堆内存 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) {//计算出mmap_sizemmap_size BIONIC_ALIGN(attr-stack_size sizeof(pthread_internal_t), 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; //创建mapp空间失败,则返回错误码}stack_top reinterpret_castuint8_t*(attr-stack_base) mmap_size;}//....return 0; }线程的分配mmap_size线程堆大小(1040k)线程结构体pthread_internal_t的大小 , 线程结构体pthread_internal_t包含了线程的名字localtread等。 接下来看下__create_thread_mapped_space() static void* __create_thread_mapped_space(size_t mmap_size, size_t stack_guard_size) {int prot PROT_READ | PROT_WRITE;int flags MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;//根据MAP_ANONYMOUS flags,分配指定mmap_size大小的匿名共享内存void* space mmap(NULL, mmap_size, prot, flags, -1, 0);if (space MAP_FAILED) {__libc_format_log(ANDROID_LOG_WARN,libc,pthread_create failed: couldnt allocate %zu-bytes mapped space: %s, mmap_size, strerror(errno));return NULL;}//....return space; }这里和Bugly上的pthread_create failed: couldnt allocate 1085440-bytes mapped space: Out of memory 对应上了,即创建线程的堆内存失败了,虚拟内存不够了。 接下来看下Linux 是如何创建新子进程即创建线程。 先来了解下一些Linux中的概念 进程创建 Linux 进程创建 通过fork(),复制资源(包含代码段、数据段、堆、栈)给子进程,但两进程内存资源不共享Linux用户级别线程创建通过pthread库中的pthread_create()创建线程共享同个进程中的资源inux内核线程创建 通过kthread_create() 在Linux看来线程是一种进程间共享资源的方式线程也可以看做跟其进程共享资源的进程。线程与进程的区别是是否共享资源。 http://aospxref.com/android-7.1.2_r39/xref/bionic/libc/bionic/clone.cpp /bionic/libc/bionic/clone.cpp int clone(int (*fn)(void*), void* child_stack, int flags, void* arg, ...) {//真正拷贝子进程过程,更多调用过程int clone_result __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg);self-set_cached_pid(parent_pid);return clone_result; }pthread_create()-linux的clone()-sys_clone()-do_fork()-copy_process(),在这个过程中,会拷贝当前进程(比如主进程)的资源, 会检查进程是超出限制(即线程是否超过最大值),fd资源是否超过限制(在linux 中socket、file都是fd),共享信号处理。 更多请阅读,http://gityuan.com/2017/08/05/linux-process-fork/ 最后看下每个code对应的异常msg: http://aospxref.com/android-7.1.2_r39/xref/bionic/libc/bionic/strerror.cpp#36 /bionic/libc/bionic/strerror.cpp char* strerror(int error_number) {// Just return the original constant in the easy cases.char* result const_castchar*(__strerror_lookup(error_number));if (result ! nullptr) {return result;}result g_strerror_tls_buffer.get();strerror_r(error_number, result, g_strerror_tls_buffer.size());return result; }http://aospxref.com/android-7.1.2_r39/xref/bionic/libc/include/sys/_errdefs.h /bionic/libc/include/sys/_errdefs.h __BIONIC_ERRDEF( EAGAIN , 11, Try again ) __BIONIC_ERRDEF( ENOMEM , 12, Out of memory ) __BIONIC_ERRDEF( EACCES , 13, Permission denied ) __BIONIC_ERRDEF( EMFILE , 24, Too many open files )这里延伸点Thread 异常捕捉处理器中 捕获到java 层异常时,不能再创建Thread,不然会抛出 InternalError:Thread starting during runtime shutdown。即异常上报的线程要提前创建。 当发生异常时,当内存不足时进行异常上报,使用OkHttp传输(会创建新线程),可能造成新的OOM 异常; 资料参考 http://gityuan.com/2016/09/24/android-thread/https://blog.csdn.net/Tencent_Bugly/article/details/78542324
http://www.sadfv.cn/news/277717/

相关文章:

  • 网站建设属于淘宝哪种类目域名怎么起
  • 付给招聘网站的费用怎么做分录开封网站建设培训班
  • 机关网站建设 方案网上国网app推广
  • 中迅做网站是模板站吗新闻媒体发稿平台
  • 上海微信网站建设公司电话公司网站建设费属于什么费用
  • 网站建设纟金手指下拉壹陆wordpress升级后怎么设置字体颜色
  • 电子商务网站建设与维护李建忠下载企业网站推广技术
  • 什么网站可以做拍a发布会搜索引擎营销的主要方式有
  • 苏州高端网站建设定制手机模板的网站
  • 先建网站还是先做网页网站建设合同的结构
  • 南京高端网站建设做购物网站的图标从哪里来
  • php5 mysql网站开发基础与应用门户网站app
  • 黑色装修网站源码dede怎样入驻微信小程序
  • 中学生怎么做网站wordpress 文章之显示标题
  • 南昌网站小程序开发企业网站建设条件
  • 有发展的小企业网站建设怎样做百度网站推广
  • 网站规划与设计就业vs 2008 建立网站
  • 网站申请免费astro wordpress
  • 专业做国际网站wordpress trego
  • 电子科技网站永定路网站建设
  • 蓝奏云注册网站如何查看网站蜘蛛
  • 新开传奇手游网站大全紫金银行网站
  • 网站开发工程师招聘要求阿里云apache重写wordpress
  • 如何利用国外网站做自媒体大数据精准营销
  • 网站后台编辑器下载海南省住房建设厅网站首页
  • 做本地网站能赚钱么wordpress文章批量编辑
  • 域名备案成功怎么做网站营销型网站建设规划书
  • 网站开发项目怎么接怎么制作糖葫芦教程
  • 河北中冶润丰建设股份有限公司网站艺术生搭建wordpress个人博客
  • 深圳专业高端网站建设费用wordpress级简主题