ANR 之 Java进程的Trace文件解析

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

接下来从虚拟机角度说说目标进程收到该信号的处理过程,每一行关键信息都说明其所对应的输出方法。

1.1 trace参数解读



"Binder_1" prio=5 tid=8 Native

  | group="main" sCount=1 dsCount=0 obj=0x12c610a0 self=0x5573e5c750

  | sysTid=12092 nice=0 cgrp=default sched=0/0 handle=0x7fa2743450

  | state=S schedstat=( 796240075 863170759 3586 ) utm=50 stm=29 core=1 HZ=100

  | stack=0x7fa2647000-0x7fa2649000 stackSize=1013KB

  | held mutexes=



  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

说明:

第0行:

线程名: Binder_1(如有daemon则代表守护线程)

prio: 线程优先级

tid: 线程内部id

线程状态: NATIVE

第1行:

group: 线程所属的线程组

sCount: 线程挂起次数

dsCount: 用于调试的线程挂起次数

obj: 当前线程关联的java线程对象

self: 当前线程地址

第2行:

sysTid:线程真正意义上的tid

nice: 调度有优先级

cgrp: 进程所属的进程调度组

sched: 调度策略

handle: 函数处理地址

第3行:

state: 线程状态

schedstat: CPU调度时间统计, 见proc/[pid]/task/[tid]/schedstat

utm/stm: 用户态/内核态的CPU时间(单位是jiffies), 见proc/[pid]/task/[tid]/stat

core: 该线程的最后运行所在核

HZ: 时钟频率

第4行:

stack:线程栈的地址区间

stackSize:栈的大小

第5行:

mutex: 所持有mutex类型,有独占锁exclusive和共享锁shared两类

schedstat含义说明:

nice值越小则优先级越高。此处nice=-2, 可见优先级还是比较高的;

schedstat括号中的3个数字依次是Running、Runable、Switch,紧接着的是utm和stm

Running时间:CPU运行的时间,单位ns

Runable时间:RQ队列的等待时间,单位ns

Switch次数:CPU调度切换次数

utm: 该线程在用户态所执行的时间,单位是jiffies,jiffies定义为sysconf(_SC_CLK_TCK),默认等于10ms

stm: 该线程在内核态所执行的时间,单位是jiffies,默认等于10ms

可见,该线程Running=186667489018ns,也约等于186667ms。在CPU运行时间包括用户态(utm)和内核态(stm)。utm + stm = (12112 + 6554) ×10 ms = 186666ms。

结论:utm + stm = schedstat第一个参数值。

1.2 涉及代码



/art/runtime/

    - signal_catcher.cc

    - runtime.cc

    - intern_table.cc

    - thread_list.cc

    - java_vm_ext.cc

    - class_linker.cc

    - gc/heap.cc



  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

二 ART信号捕获

=========

2.1 SignalCatcher


SignalCatcher.cc


void* SignalCatcher::Run(void* arg) {

  SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg);

  Runtime* runtime = Runtime::Current();

  

  Thread* self = Thread::Current();

  //当前进程状态处于非Runnable是

  DCHECK_NE(self->GetState(), kRunnable);

  {

    MutexLock mu(self, signal_catcher->lock_);

    signal_catcher->thread_ = self;

    signal_catcher->cond_.Broadcast(self);

  }



  //设置需要handle的信号

  SignalSet signals;

  signals.Add(SIGQUIT); //信号3

  signals.Add(SIGUSR1); //信号10



  while (true) {

    int signal_number = signal_catcher->WaitForSignal(self, signals);

    if (signal_catcher->ShouldHalt()) {

      runtime->DetachCurrentThread();

      return nullptr;

    }



    switch (signal_number) {

    case SIGQUIT:

      //收到信号3 【见小节2.2】

      signal_catcher->HandleSigQuit();

      break;

    case SIGUSR1:

      signal_catcher->HandleSigUsr1();

      break;

    default:

      LOG(ERROR) << "Unexpected signal %d" << signal_number;

      break;

    }

  }

}



  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

2.2 SignalCatcher::HandleSigQuit


signal_catcher.cc


void SignalCatcher::HandleSigQuit() {

  Runtime* runtime = Runtime::Current();

  std::ostringstream os;

  os << "\n" << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";



  DumpCmdLine(os);



  std::string fingerprint = runtime->GetFingerprint();

  os << "Build fingerprint: '" << (fingerprint.empty() ? "unknown" : fingerprint) << "'\n";

  os << "ABI: '" << GetInstructionSetString(runtime->GetInstructionSet()) << "'\n";

  os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";

  // [见小节2.3]

  runtime->DumpForSigQuit(os);



  os << "----- end " << getpid() << " -----\n";

  // [见小节3.7]

  Output(os.str());

}



  • 1

  • 2

最后:学习总结——MyBtis知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

image

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

nSet()) << “'\n”;

os << "Build type: " << (kIsDebugBuild ? “debug” : “optimized”) << “\n”;

// [见小节2.3]

runtime->DumpForSigQuit(os);

os << “----- end " << getpid() << " -----\n”;

// [见小节3.7]

Output(os.str());

}




*   1

    

*   2


## 最后:学习总结——MyBtis知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

[外链图片转存中...(img-zh5arUAu-1725868078775)]

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值