乐趣区

关于android:浅析ThreadList的runcheckpoint方法

作用

threadlist 的 runcheckpoint 办法 作用是让所有线程都执行制订的工作。threadlist 的 dump 办法有两种实现形式:

1。打印调用者线程的栈帧状况

2。打印指定 thread 线程的栈帧状况。

依据下面两个函数置信大家能够猜到能够做哪些骚操作了。接下来持续解释

函数实现

runcheckpoint 函数实现:

1。针对曾经在运行的线程只需对这个线程设置 kcheckpoint 标记位,运行中的线程查看到 kcheckpoint 会主动打印以后线程的信息。而针对不在运行的线程须要先设置 suspendrequest 标记位让他们暂停运行,避免之后暂停的线程状态变为运行。所以针对曾经运行的线程来说只有设置标记位即可,thread 运行的时候会在特定指令处进行 checkpoint 办法进行查看标记位而作出对应的解决。

标记位品种:

1.kcheckpoint 的标记位是取出本人 tls 区域的 closure 并执行指定 run 函数最多三个:通过 tls 区域保留 须要执行的 run 函数。run 函数通过 closure 闭包封装。一个线程做多能够执行三个 closure,也就是能够执行三个 run 办法。可通过 add 的形式进行增加对应线程 tls 区域的 closure。

2.suspendrequest 标记位是将线程状态设置为 suspend 暂停不运行。

解释:

threadlist 中寄存着所有的线程也晓得所有运行的线程数是多少

将所有线程都暂停怎么验证呢?

假如以后 threadlist 中有 5 个运行的线程数量通过 suspendbarrier 保留为 5,我给所有的线程都设置 ksuspendrequest 标记位,当它们碰到某些指令时比方循环返回,异样指令处办法返回处等指令处时会运行 runcheckpoint 查看本人的标记位。而 suspendrequest 对应的第一步操作就是递加 suspendbarrir 而后挂起本人批改本人线程状态,当递加为 0 时代表所有线程都暂停了。这个时候就是所有线程都暂停。递加操作是无锁编程通过循环递加 barrry,通过 cas 原子操作保障线程平安

如果要是不在运行的线程呢?就是说这个 线程阻塞了或者曾经暂停了他都没有运行那么怎么进行查看标记位呢 这个也就是下面说过的 dump 的第二种实现形式,不须要那个指定的线程运行本人打印本人线程的状况,而是通过调用者线程 (你这个线程不运行,调用者线程运行我用调用者线程去打印) 进行帮忙那些没有运行的线程打印信息,只须要指定对应的 thread。

下面第一步设置 ksuspendrequest 标记位曾经让不在运行的线程都曾经进行运行了(即便暂停的线程复原运行也会在查看标记位的时候进行把本人暂停)而后我把一个执行 dump 函数的 run 函数封装成 closure 增加到 threadlist 中的每一个线程中。而 dump 函数是打印指定线程的栈帧信息。这里 runcheckpoint 都是通过指定线程的形式来打印对应指定线程的信息,执行线程是以后线程,然而打印对应线程状况的是指定的线程

为什么呢?因为要保留线程不能产生任何内存上的变动所以只能通过将所有线程都 suspend 的形式实现,然而线程暂停了怎么可能打印本人的信息呢?所以得留一个活着的线程也就是以后线程去打印他们的信息

总结

查看标记位的操作之后就会查看到本人线程被设置了 kcheckpoint 标记位从 tsl 区域中取出 closure 执行工作;设置失败代表以后线程不在运行状态,那么也不能够间接打印那个线程的信息,因为之后这个线程可能再次运行会扭转线程的内存状况,所以针对暂停的线程还须要设置 ksuspendpoint 保障即便线程之后运行也会再次暂停(递加 barrier 胜利才会返回 true),这样就能保障以后是产生状况的现场对应的状况。

思考环节

大家认真想想是不是咱们 anr 的时候查看 trace 文件会呈现一堆线程的信息不论是 native 的还是 java 的都会呈现。答案就是通过 threadlist 的 runcheckpoint 实现的。

运行的线程保障及时的打印过后虚拟机中所有线程状况,不在运行的线程设置挂起标记位保障即便运行也能保障不会毁坏现场。因为线程状态切换时也会进行一次标记位查看所以能够保障是之前那次收回指令时的内存状况。

退出移动版